diff --git a/docs/api-inventory.json b/docs/api-inventory.json index 53b0d85a..2484f037 100644 --- a/docs/api-inventory.json +++ b/docs/api-inventory.json @@ -1,4787 +1,15838 @@ [ - { - "surface": "core-apitokens", - "endpoints": [ + { + "surface": "core-apitokens", + "endpoints": [ + { + "method": "GET", + "path": "/api/apitokens", + "auth": "jwt", + "params": "not documented", + "purpose": "List the caller's own tokens. Admins may pass ?all=true for everyone's.", + "example": "curl http://localhost:5001/api/apitokens -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "all", + "type": "string", + "required": false, + "default": "false" + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/apitokens", - "auth": "jwt", - "params": "not documented", - "purpose": "List the caller's own tokens. Admins may pass ?all=true for everyone's.", - "example": "curl http://localhost:5001/api/apitokens -H \"Authorization: Bearer $TOK\"" + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "member token", + "resourcescopes": null, + "scopes": null, + "tokenid": 2, + "tokenprefix": "", + "userid": 2, + "username": "" }, { - "method": "POST", - "path": "/api/apitokens", - "auth": "permission:apitokens.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a token for the caller. Returns the full secret ONCE.", - "example": "curl -X POST http://localhost:5001/api/apitokens -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/apitokens/", - "auth": "permission:apitokens.create", - "params": "path: tokenid (int)", - "purpose": "Revoke (deactivate) a token. Own token, or any if admin.", - "example": "curl -X DELETE http://localhost:5001/api/apitokens/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/apitokens/", - "auth": "permission:apitokens.create", - "params": "path: tokenid (int); body: JSON (fields not yet documented)", - "purpose": "Rename, rescope, or deactivate a token. Own token, or any if admin.", - "example": "curl -X PUT http://localhost:5001/api/apitokens/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "admin token", + "resourcescopes": null, + "scopes": null, + "tokenid": 1, + "tokenprefix": "", + "userid": 1, + "username": "" } - ] - }, - { - "surface": "core-applications", - "endpoints": [ - { - "method": "GET", - "path": "/api/applications", - "auth": "permission:applications.view", - "params": "not documented", - "purpose": "List all applications.", - "example": "curl http://localhost:5001/api/applications -H \"Authorization: Bearer $TOK\"" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/apitokens", + "auth": "permission:apitokens.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a token for the caller. Returns the full secret ONCE.", + "example": "curl -X POST http://localhost:5001/api/apitokens -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "name": "display svc", + "resourcescopes": [ + "gea-shopfloor-display" + ], + "scopes": [ + "geenforce.fetch" + ] + }, + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "display svc", + "resourcescopes": [ + "gea-shopfloor-display" + ], + "scopes": [ + "geenforce.fetch" + ], + "secret": "", + "tokenid": 1, + "tokenprefix": "", + "userid": 1, + "warning": "Save this token now. It will not be shown again. Store it somewhere safe." + }, + "message": "Token created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/apitokens/", + "auth": "permission:apitokens.create", + "params": "path: tokenid (int)", + "purpose": "Revoke (deactivate) a token. Own token, or any if admin.", + "example": "curl -X DELETE http://localhost:5001/api/apitokens/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Token revoked", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/apitokens/", + "auth": "permission:apitokens.create", + "params": "path: tokenid (int); body: JSON (fields not yet documented)", + "purpose": "Rename, rescope, or deactivate a token. Own token, or any if admin.", + "example": "curl -X PUT http://localhost:5001/api/apitokens/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "scopes": [ + "applications.edit" + ] + }, + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "test token", + "resourcescopes": null, + "scopes": [ + "applications.edit" + ], + "tokenid": 1, + "tokenprefix": "", + "userid": 1 + }, + "message": "Token updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + } + ] + }, + { + "surface": "core-applications", + "endpoints": [ + { + "method": "GET", + "path": "/api/applications", + "auth": "permission:applications.view", + "params": "not documented", + "purpose": "List all applications.", + "example": "curl http://localhost:5001/api/applications -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "appname", + "type": "string", + "required": false + }, + { + "name": "installable", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "showhidden", + "type": "string", + "required": false, + "default": "false" + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/applications", + "auth": "permission:applications.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new application.", + "example": "curl -X POST http://localhost:5001/api/applications -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "appname": "Monitored App", + "ismonitorable": true, + "monitorlaunchpath": "C:\\Vendor\\app.exe", + "monitorprocessname": "app.exe" + }, + "responseexample": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Fleet App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": null, + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "policynote": "A configuration policy was created for this application, but it is not attached to any business policy and installs nothing until an admin adds it to one.", + "policyresult": "created", + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Application created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/applications/", + "auth": "permission:applications.delete", + "params": "path: app_id (int)", + "purpose": "Permanently delete an application, its versions, and its uploads.", + "example": "curl -X DELETE http://localhost:5001/api/applications/1 -H \"Authorization: Bearer $TOK\"", + "requestexample": { + "confirm": "OK" + }, + "responseexample": { + "data": { + "deactivatedpolicies": [ + "Required app: Doomed", + "Hand made push" + ], + "policyresult": "kept" + }, + "message": "Application deleted; deactivated 2 policy(ies) that referenced it: Required app: Doomed, Hand made push", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/applications/", + "auth": "permission:applications.view", + "params": "path: app_id (int)", + "purpose": "Get a single application with details.", + "example": "curl http://localhost:5001/api/applications/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "TeamApp", + "contacts": [ + { + "name": "Alice", + "sso": "a01" + } + ], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": null, + "installedcount": 0, + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "knowledgebase": [], + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "supportteamid": 1, + "supportteamname": "Controls", + "teamurl": "https://sn.example/controls", + "versions": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/applications/", + "auth": "permission:applications.edit", + "params": "path: app_id (int); body: JSON (fields not yet documented)", + "purpose": "Update an application.", + "example": "curl -X PUT http://localhost:5001/api/applications/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "ismonitorable": false, + "monitorlaunchpath": "", + "monitorprocessname": "" + }, + "responseexample": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": null, + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "policynote": "A configuration policy was created for this application, but it is not attached to any business policy and installs nothing until an admin adds it to one.", + "policyresult": "created", + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Application updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/applications//image", + "auth": "permission:applications.edit", + "params": "path: app_id (int)", + "purpose": "Remove an application's image and clear the field.", + "example": "curl -X DELETE http://localhost:5001/api/applications/1/image -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/applications//image", + "auth": "permission:applications.edit", + "params": "path: app_id (int); body: JSON (fields not yet documented)", + "purpose": "Upload (or replace) an application's image.", + "example": "curl -X POST http://localhost:5001/api/applications/1/image -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": "/api/applications/image/application-1.png", + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Application image uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/applications//installed", + "auth": "permission:applications.view", + "params": "path: app_id (int)", + "purpose": "List all computers that have this application installed.", + "example": "curl http://localhost:5001/api/applications/1/installed -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "DELETE", + "path": "/api/applications//package", + "auth": "permission:applications.edit", + "params": "path: app_id (int)", + "purpose": "Remove an uploaded installer and clear the path it set.", + "example": "curl -X DELETE http://localhost:5001/api/applications/1/package -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": null, + "installersha256": null, + "installpath": "", + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Installer removed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/applications//package", + "auth": "permission:applications.edit", + "params": "path: app_id (int); body: JSON (fields not yet documented)", + "purpose": "Upload (or replace) the installer for an application.", + "example": "curl -X POST http://localhost:5001/api/applications/1/package -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "appversionid": null, + "bytes": 130, + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "detectedversion": "", + "documentationpath": null, + "image": null, + "installersha256": "", + "installpath": "/api/applications/package/1/setup.exe", + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "sha256": "", + "supportteamid": null, + "supportteamname": null, + "teamurl": null, + "uploadedfilename": "setup.exe" + }, + "message": "Installer uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/applications//revert", + "auth": "permission:applications.edit", + "params": "path: app_id (int); body: JSON (fields not yet documented)", + "purpose": "Strip an application back to a catalogue record.", + "example": "curl -X POST http://localhost:5001/api/applications/1/revert -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "confirm": "OK" + }, + "responseexample": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": "/api/applications/image/application-1.png", + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Application reverted to record", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/applications//versions", + "auth": "permission:applications.view", + "params": "path: app_id (int)", + "purpose": "List all versions for an application.", + "example": "curl http://localhost:5001/api/applications/1/versions -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/applications//versions", + "auth": "permission:applications.create", + "params": "path: app_id (int); body: JSON (fields not yet documented)", + "purpose": "Create a new version for an application.", + "example": "curl -X POST http://localhost:5001/api/applications/1/versions -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "sha256": "", + "silentargs": "/S /v/qn", + "version": "1.2.3" + }, + "responseexample": { + "data": { + "appid": 1, + "appversionid": 1, + "dateadded": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "notes": null, + "releasedate": null, + "sha256": "", + "silentargs": "/S /v/qn", + "version": "1.2.3" + }, + "message": "Version created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/applications/image/", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "path: filename (path)", + "purpose": "Serve an uploaded application image.", + "example": "curl http://localhost:5001/api/applications/image/example.png" + }, + { + "method": "GET", + "path": "/api/applications/machines/", + "auth": "permission:applications.view", + "params": "path: machine_id (int)", + "purpose": "List all applications installed on a computer.", + "example": "curl http://localhost:5001/api/applications/machines/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "POST", - "path": "/api/applications", - "auth": "permission:applications.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new application.", - "example": "curl -X POST http://localhost:5001/api/applications -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/applications/", - "auth": "permission:applications.delete", - "params": "path: app_id (int)", - "purpose": "Permanently delete an application, its versions, and its uploads.", - "example": "curl -X DELETE http://localhost:5001/api/applications/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/applications/", - "auth": "permission:applications.view", - "params": "path: app_id (int)", - "purpose": "Get a single application with details.", - "example": "curl http://localhost:5001/api/applications/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/applications/", - "auth": "permission:applications.edit", - "params": "path: app_id (int); body: JSON (fields not yet documented)", - "purpose": "Update an application.", - "example": "curl -X PUT http://localhost:5001/api/applications/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/applications//image", - "auth": "permission:applications.edit", - "params": "path: app_id (int)", - "purpose": "Remove an application's image and clear the field.", - "example": "curl -X DELETE http://localhost:5001/api/applications/1/image -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/applications//image", - "auth": "permission:applications.edit", - "params": "path: app_id (int); body: JSON (fields not yet documented)", - "purpose": "Upload (or replace) an application's image.", - "example": "curl -X POST http://localhost:5001/api/applications/1/image -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/applications//installed", - "auth": "permission:applications.view", - "params": "path: app_id (int)", - "purpose": "List all computers that have this application installed.", - "example": "curl http://localhost:5001/api/applications/1/installed -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "DELETE", - "path": "/api/applications//package", - "auth": "permission:applications.edit", - "params": "path: app_id (int)", - "purpose": "Remove an uploaded installer and clear the path it set.", - "example": "curl -X DELETE http://localhost:5001/api/applications/1/package -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/applications//package", - "auth": "permission:applications.edit", - "params": "path: app_id (int); body: JSON (fields not yet documented)", - "purpose": "Upload (or replace) the installer for an application.", - "example": "curl -X POST http://localhost:5001/api/applications/1/package -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/applications//revert", - "auth": "permission:applications.edit", - "params": "path: app_id (int); body: JSON (fields not yet documented)", - "purpose": "Strip an application back to a catalogue record.", - "example": "curl -X POST http://localhost:5001/api/applications/1/revert -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/applications//versions", - "auth": "permission:applications.view", - "params": "path: app_id (int)", - "purpose": "List all versions for an application.", - "example": "curl http://localhost:5001/api/applications/1/versions -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/applications//versions", - "auth": "permission:applications.create", - "params": "path: app_id (int); body: JSON (fields not yet documented)", - "purpose": "Create a new version for an application.", - "example": "curl -X POST http://localhost:5001/api/applications/1/versions -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/applications/image/", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "path: filename (path)", - "purpose": "Serve an uploaded application image.", - "example": "curl http://localhost:5001/api/applications/image/example.png" - }, - { - "method": "GET", - "path": "/api/applications/machines/", - "auth": "permission:applications.view", - "params": "path: machine_id (int)", - "purpose": "List all applications installed on a computer.", - "example": "curl http://localhost:5001/api/applications/machines/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/applications/machines/", - "auth": "permission:applications.create", - "params": "path: machine_id (int); body: JSON (fields not yet documented)", - "purpose": "Install an application on a computer.", - "example": "curl -X POST http://localhost:5001/api/applications/machines/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/applications/machines//", - "auth": "permission:applications.delete", - "params": "path: machine_id (int), app_id (int)", - "purpose": "Uninstall an application from a computer.", - "example": "curl -X DELETE http://localhost:5001/api/applications/machines/1/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/applications/machines//", - "auth": "permission:applications.edit", - "params": "path: machine_id (int), app_id (int); body: JSON (fields not yet documented)", - "purpose": "Update installed application (e.g., change version).", - "example": "curl -X PUT http://localhost:5001/api/applications/machines/1/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/applications/package/", - "auth": "permission:applications.download", - "params": "path: filename (path)", - "purpose": "Download an uploaded installer.", - "example": "curl http://localhost:5001/api/applications/package/example.png -H \"Authorization: Bearer $TOK\"" + "appdescription": null, + "appid": 1, + "appname": "Test App", + "appversionid": null, + "computerid": 1, + "id": 1, + "installeddate": "2026-01-01T00:00:00.000000Z", + "installedversion": "1.2.3", + "isactive": true } - ] - }, - { - "surface": "core-assets", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/applications/machines/", + "auth": "permission:applications.create", + "params": "path: machine_id (int); body: JSON (fields not yet documented)", + "purpose": "Install an application on a computer.", + "example": "curl -X POST http://localhost:5001/api/applications/machines/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/applications/machines//", + "auth": "permission:applications.delete", + "params": "path: machine_id (int), app_id (int)", + "purpose": "Uninstall an application from a computer.", + "example": "curl -X DELETE http://localhost:5001/api/applications/machines/1/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/applications/machines//", + "auth": "permission:applications.edit", + "params": "path: machine_id (int), app_id (int); body: JSON (fields not yet documented)", + "purpose": "Update installed application (e.g., change version).", + "example": "curl -X PUT http://localhost:5001/api/applications/machines/1/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/applications/package/", + "auth": "permission:applications.download", + "params": "path: filename (path)", + "purpose": "Download an uploaded installer.", + "example": "curl http://localhost:5001/api/applications/package/example.png -H \"Authorization: Bearer $TOK\"" + } + ] + }, + { + "surface": "core-assets", + "endpoints": [ + { + "method": "GET", + "path": "/api/assets", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all assets with filtering and pagination.", + "example": "curl http://localhost:5001/api/assets -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "businessunit_id", + "type": "integer", + "required": false + }, + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "dir", + "type": "string", + "required": false, + "default": "asc" + }, + { + "name": "include_type_data", + "type": "string", + "required": false, + "default": "false" + }, + { + "name": "location_id", + "type": "integer", + "required": false + }, + { + "name": "locationid", + "type": "integer", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "sort", + "type": "string", + "required": false, + "default": "assetnumber" + }, + { + "name": "status_id", + "type": "integer", + "required": false + }, + { + "name": "statusid", + "type": "integer", + "required": false + }, + { + "name": "type", + "type": "string", + "required": false + }, + { + "name": "type_id", + "type": "integer", + "required": false + }, + { + "name": "typeid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/assets", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all assets with filtering and pagination.", - "example": "curl http://localhost:5001/api/assets -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/assets", - "auth": "permission:assets.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new asset.", - "example": "curl -X POST http://localhost:5001/api/assets -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/assets/", - "auth": "permission:assets.delete", - "params": "path: asset_id (int)", - "purpose": "Delete (soft delete) an asset.", - "example": "curl -X DELETE http://localhost:5001/api/assets/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/assets/", - "auth": "permission:assets.view", - "params": "path: asset_id (int)", - "purpose": "Get a single asset with full details.", - "example": "curl http://localhost:5001/api/assets/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/assets/", - "auth": "permission:assets.edit", - "params": "path: asset_id (int); body: JSON (fields not yet documented)", - "purpose": "Update an asset.", - "example": "curl -X PUT http://localhost:5001/api/assets/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/assets//communications", - "auth": "permission:assets.view", - "params": "path: asset_id (int)", - "purpose": "Get all communications for an asset.", - "example": "curl http://localhost:5001/api/assets/1/communications -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/assets//relationships", - "auth": "permission:assets.view", - "params": "path: asset_id (int)", - "purpose": "Get all relationships for an asset.", - "example": "curl http://localhost:5001/api/assets/1/relationships -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/assets/lookup/", - "auth": "permission:assets.view", - "params": "path: assetnumber (string)", - "purpose": "Look up an asset by its asset number.", - "example": "curl http://localhost:5001/api/assets/lookup/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/assets/map", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Get all assets with map positions for unified floor map display.", - "example": "curl http://localhost:5001/api/assets/map -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/assets/relationships", - "auth": "permission:assets.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a relationship between two assets.", - "example": "curl -X POST http://localhost:5001/api/assets/relationships -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/assets/relationships/", - "auth": "permission:assets.delete", - "params": "path: rel_id (int)", - "purpose": "Delete an asset relationship.", - "example": "curl -X DELETE http://localhost:5001/api/assets/relationships/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/assets/relationshiptypes", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all asset relationship types.", - "example": "curl http://localhost:5001/api/assets/relationshiptypes -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/assets/relationshiptypes", - "auth": "permission:assets.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new asset relationship type.", - "example": "curl -X POST http://localhost:5001/api/assets/relationshiptypes -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/assets/relationshiptypes/", - "auth": "permission:assets.delete", - "params": "path: type_id (int)", - "purpose": "Delete a relationship type. Refused if any relationship still uses it.", - "example": "curl -X DELETE http://localhost:5001/api/assets/relationshiptypes/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/assets/relationshiptypes/", - "auth": "permission:assets.edit", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a relationship type.", - "example": "curl -X PUT http://localhost:5001/api/assets/relationshiptypes/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/assets/statuses", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all asset statuses.", - "example": "curl http://localhost:5001/api/assets/statuses -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/assets/statuses", - "auth": "permission:assets.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new asset status.", - "example": "curl -X POST http://localhost:5001/api/assets/statuses -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/assets/statuses/", - "auth": "permission:assets.delete", - "params": "path: status_id (int)", - "purpose": "Delete an asset status. Refused if any asset still uses it.", - "example": "curl -X DELETE http://localhost:5001/api/assets/statuses/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/assets/statuses/", - "auth": "permission:assets.view", - "params": "path: status_id (int)", - "purpose": "Get a single asset status.", - "example": "curl http://localhost:5001/api/assets/statuses/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/assets/statuses/", - "auth": "permission:assets.edit", - "params": "path: status_id (int); body: JSON (fields not yet documented)", - "purpose": "Update an asset status.", - "example": "curl -X PUT http://localhost:5001/api/assets/statuses/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/assets/types", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all asset types.", - "example": "curl http://localhost:5001/api/assets/types -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/assets/types", - "auth": "permission:assets.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new asset type.", - "example": "curl -X POST http://localhost:5001/api/assets/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/assets/types/", - "auth": "permission:assets.view", - "params": "path: type_id (int)", - "purpose": "Get a single asset type.", - "example": "curl http://localhost:5001/api/assets/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/assets/types/", - "auth": "permission:assets.edit", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update an asset type's display fields (color/icon/description). The name, plugin, and table are structural and not editable here.", - "example": "curl -X PUT http://localhost:5001/api/assets/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "assetid": 1, + "assetnumber": "A-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "machine", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "mill", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "serialnumber": "", + "statusid": 1 } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/assets", + "auth": "permission:assets.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new asset.", + "example": "curl -X POST http://localhost:5001/api/assets -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/assets/", + "auth": "permission:assets.delete", + "params": "path: asset_id (int)", + "purpose": "Delete (soft delete) an asset.", + "example": "curl -X DELETE http://localhost:5001/api/assets/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/assets/", + "auth": "permission:assets.view", + "params": "path: asset_id (int)", + "purpose": "Get a single asset with full details.", + "example": "curl http://localhost:5001/api/assets/1 -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "include_type_data", + "type": "string", + "required": false, + "default": "true" + } ] - }, - { - "surface": "core-auditlogs", - "endpoints": [ - { - "method": "GET", - "path": "/api/auditlogs", - "auth": "permission:audit.view", - "params": "not documented", - "purpose": "List audit logs with filtering and pagination.", - "example": "curl http://localhost:5001/api/auditlogs -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/assets/", + "auth": "permission:assets.edit", + "params": "path: asset_id (int); body: JSON (fields not yet documented)", + "purpose": "Update an asset.", + "example": "curl -X PUT http://localhost:5001/api/assets/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/assets//communications", + "auth": "permission:assets.view", + "params": "path: asset_id (int)", + "purpose": "Get all communications for an asset.", + "example": "curl http://localhost:5001/api/assets/1/communications -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/assets//relationships", + "auth": "permission:assets.view", + "params": "path: asset_id (int)", + "purpose": "Get all relationships for an asset.", + "example": "curl http://localhost:5001/api/assets/1/relationships -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "incoming": [ + { + "createddate": "2026-01-01T00:00:00.000000Z", + "inheritsposition": true, + "isactive": true, + "isdirectional": true, + "label": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "relationshipid": 1, + "relationshiptypeid": 1, + "relationshiptypename": "controls", + "sourceasset": { + "assetid": 1, + "assetnumber": "PC-1", + "assettypecolor": null, + "assettypeid": 2, + "assettypename": "computer", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "serialnumber": "", + "statusid": 1 + }, + "sourceassetid": 1, + "targetassetid": 2 + } + ], + "outgoing": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/assets/lookup/", + "auth": "permission:assets.view", + "params": "path: assetnumber (string)", + "purpose": "Look up an asset by its asset number.", + "example": "curl http://localhost:5001/api/assets/lookup/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/assets/map", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Get all assets with map positions for unified floor map display.", + "example": "curl http://localhost:5001/api/assets/map -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "assettype", + "type": "string", + "required": false + }, + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "locationid", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "statusid", + "type": "integer", + "required": false + }, + { + "name": "subtype", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": { + "assets": [ + { + "assetid": 1, + "assetnumber": "2007", + "assettype": "machine", + "assettypeid": 1, + "businessunit": null, + "businessunitid": null, + "displayname": "", + "levelid": null, + "location": null, + "locationid": null, + "mapx": 100, + "mapy": 100, + "name": null, + "primaryip": null, + "serialnumber": "", + "status": null, + "statuscolor": null, + "statusid": 1, + "typedata": { + "assetid": 1, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": null, + "machineid": 1, + "machinetypeid": null, + "maintenanceintervaldays": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": null, + "requiresmanualconfig": false, + "vendorid": null + } + }, + { + "assetid": 2, + "assetnumber": "2008", + "assettype": "machine", + "assettypeid": 1, + "businessunit": null, + "businessunitid": null, + "displayname": "", + "levelid": null, + "location": null, + "locationid": null, + "mapx": 110, + "mapy": 110, + "name": null, + "primaryip": null, + "serialnumber": "", + "status": null, + "statuscolor": null, + "statusid": 1, + "typedata": { + "assetid": 2, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": null, + "machineid": 2, + "machinetypeid": null, + "maintenanceintervaldays": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": null, + "requiresmanualconfig": false, + "vendorid": null + } + } + ], + "filters": { + "assettypes": [ + { + "assettype": "machine", + "assettypeid": 1, + "color": null, + "icon": null + } + ], + "businessunits": [], + "locations": [], + "statuses": [], + "subtypes": { + "Computer": [], + "Machine": [], + "Measuring Tool": [], + "Network Device": [], + "Printer": [] + } }, + "total": 2 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/assets/relationships", + "auth": "permission:assets.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a relationship between two assets.", + "example": "curl -X POST http://localhost:5001/api/assets/relationships -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "relationshiptypeid": 1, + "sourceassetid": 1, + "targetassetid": 2 + }, + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "inheritsposition": true, + "isactive": true, + "label": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "propagated": [ + { + "createddate": "2026-01-01T00:00:00.000000Z", + "inheritsposition": true, + "isactive": true, + "label": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "relationshipid": 3, + "relationshiptypeid": 1, + "sourceassetid": 1, + "targetassetid": 3 + } + ], + "propagatedcount": 1, + "relationshipid": 2, + "relationshiptypeid": 1, + "sourceassetid": 1, + "targetassetid": 2 + }, + "message": "Relationship created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/assets/relationships/", + "auth": "permission:assets.delete", + "params": "path: rel_id (int)", + "purpose": "Delete an asset relationship.", + "example": "curl -X DELETE http://localhost:5001/api/assets/relationships/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Relationship deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/assets/relationshiptypes", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all asset relationship types.", + "example": "curl http://localhost:5001/api/assets/relationshiptypes -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/auditlogs/entity//", - "auth": "permission:audit.view", - "params": "path: entitytype (string), entityid (int)", - "purpose": "Get audit history for a specific entity.", - "example": "curl http://localhost:5001/api/auditlogs/entity/x/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/auditlogs/purge", - "auth": "permission:audit.purge", - "params": "body: JSON (fields not yet documented)", - "purpose": "Delete entries older than the retention window.", - "example": "curl -X POST http://localhost:5001/api/auditlogs/purge -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/auditlogs/retention", - "auth": "permission:audit.view", - "params": "not documented", - "purpose": "Size of the log and what the configured retention would remove.", - "example": "curl http://localhost:5001/api/auditlogs/retention -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/auditlogs/stats", - "auth": "permission:audit.view", - "params": "not documented", - "purpose": "Get audit log statistics.", - "example": "curl http://localhost:5001/api/auditlogs/stats -H \"Authorization: Bearer $TOK\"" + "color": null, + "description": null, + "isdirectional": false, + "propagatesthrough": [], + "relationshiptype": "WiFi", + "relationshiptypeid": 1 } - ] - }, - { - "surface": "core-auth", - "endpoints": [ - { - "method": "POST", - "path": "/api/auth/change-password", - "auth": "jwt", - "params": "body: JSON (fields not yet documented)", - "purpose": "Change the authenticated user's own password.", - "example": "curl -X POST http://localhost:5001/api/auth/change-password -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/assets/relationshiptypes", + "auth": "permission:assets.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new asset relationship type.", + "example": "curl -X POST http://localhost:5001/api/assets/relationshiptypes -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "isdirectional": false, + "relationshiptype": "Dualpath" + }, + "responseexample": { + "data": { + "color": null, + "description": null, + "isdirectional": true, + "propagatesthrough": [], + "relationshiptype": "Backup For", + "relationshiptypeid": 1 + }, + "message": "Relationship type created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/assets/relationshiptypes/", + "auth": "permission:assets.delete", + "params": "path: type_id (int)", + "purpose": "Delete a relationship type. Refused if any relationship still uses it.", + "example": "curl -X DELETE http://localhost:5001/api/assets/relationshiptypes/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/assets/relationshiptypes/", + "auth": "permission:assets.edit", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a relationship type.", + "example": "curl -X PUT http://localhost:5001/api/assets/relationshiptypes/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "isdirectional": false + }, + "responseexample": { + "data": { + "color": null, + "description": null, + "isdirectional": false, + "propagatesthrough": [], + "relationshiptype": "USB", + "relationshiptypeid": 1 + }, + "message": "Relationship type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/assets/statuses", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all asset statuses.", + "example": "curl http://localhost:5001/api/assets/statuses -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 }, - { - "method": "POST", - "path": "/api/auth/login", - "auth": "none (the login surface itself; rate limited, 5-strike lockout)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Authenticate user and return JWT tokens.", - "example": "curl -X POST http://localhost:5001/api/auth/login -H 'Content-Type: application/json' -d '{}'" + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/assets/statuses", + "auth": "permission:assets.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new asset status.", + "example": "curl -X POST http://localhost:5001/api/assets/statuses -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/assets/statuses/", + "auth": "permission:assets.delete", + "params": "path: status_id (int)", + "purpose": "Delete an asset status. Refused if any asset still uses it.", + "example": "curl -X DELETE http://localhost:5001/api/assets/statuses/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/assets/statuses/", + "auth": "permission:assets.view", + "params": "path: status_id (int)", + "purpose": "Get a single asset status.", + "example": "curl http://localhost:5001/api/assets/statuses/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/assets/statuses/", + "auth": "permission:assets.edit", + "params": "path: status_id (int); body: JSON (fields not yet documented)", + "purpose": "Update an asset status.", + "example": "curl -X PUT http://localhost:5001/api/assets/statuses/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/assets/types", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all asset types.", + "example": "curl http://localhost:5001/api/assets/types -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 }, - { - "method": "POST", - "path": "/api/auth/logout", - "auth": "jwt", - "params": "body: JSON (fields not yet documented)", - "purpose": "Logout user (for frontend token cleanup).", - "example": "curl -X POST http://localhost:5001/api/auth/logout -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/assets/types", + "auth": "permission:assets.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new asset type.", + "example": "curl -X POST http://localhost:5001/api/assets/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/assets/types/", + "auth": "permission:assets.view", + "params": "path: type_id (int)", + "purpose": "Get a single asset type.", + "example": "curl http://localhost:5001/api/assets/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/assets/types/", + "auth": "permission:assets.edit", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update an asset type's display fields (color/icon/description). The name, plugin, and table are structural and not editable here.", + "example": "curl -X PUT http://localhost:5001/api/assets/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "core-auditlogs", + "endpoints": [ + { + "method": "GET", + "path": "/api/auditlogs", + "auth": "permission:audit.view", + "params": "not documented", + "purpose": "List audit logs with filtering and pagination.", + "example": "curl http://localhost:5001/api/auditlogs -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "action", + "type": "string", + "required": false + }, + { + "name": "entitytype", + "type": "string", + "required": false + }, + { + "name": "from_date", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "perpage", + "type": "integer", + "required": false, + "default": 50 + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "to_date", + "type": "string", + "required": false + }, + { + "name": "userid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 50, + "total": 0, + "totalpages": 0 }, - { - "method": "GET", - "path": "/api/auth/me", - "auth": "jwt", - "params": "not documented", - "purpose": "Get current authenticated user info.", - "example": "curl http://localhost:5001/api/auth/me -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/auth/refresh", - "auth": "jwt (refresh token)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Refresh access token using refresh token.", - "example": "curl -X POST http://localhost:5001/api/auth/refresh -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/auditlogs/entity//", + "auth": "permission:audit.view", + "params": "path: entitytype (string), entityid (int)", + "purpose": "Get audit history for a specific entity.", + "example": "curl http://localhost:5001/api/auditlogs/entity/x/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/auditlogs/purge", + "auth": "permission:audit.purge", + "params": "body: JSON (fields not yet documented)", + "purpose": "Delete entries older than the retention window.", + "example": "curl -X POST http://localhost:5001/api/auditlogs/purge -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "GET", + "path": "/api/auditlogs/retention", + "auth": "permission:audit.view", + "params": "not documented", + "purpose": "Size of the log and what the configured retention would remove.", + "example": "curl http://localhost:5001/api/auditlogs/retention -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "expired": 0, + "newest": "2026-01-01T00:00:00.000000", + "oldest": "2026-01-01T00:00:00.000000", + "retentiondays": 30, + "total": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/auditlogs/stats", + "auth": "permission:audit.view", + "params": "not documented", + "purpose": "Get audit log statistics.", + "example": "curl http://localhost:5001/api/auditlogs/stats -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "actions": {}, + "activeUsers": [], + "entities": {}, + "recentCount": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-auth", + "endpoints": [ + { + "method": "POST", + "path": "/api/auth/change-password", + "auth": "jwt", + "params": "body: JSON (fields not yet documented)", + "purpose": "Change the authenticated user's own password.", + "example": "curl -X POST http://localhost:5001/api/auth/change-password -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "current_password": "", + "new_password": "" + }, + "responseexample": { + "data": { + "mustchangepassword": "" + }, + "message": "Password changed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/auth/login", + "auth": "none (the login surface itself; rate limited, 5-strike lockout)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Authenticate user and return JWT tokens.", + "example": "curl -X POST http://localhost:5001/api/auth/login -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "password": "", + "username": "" + }, + "responseexample": { + "data": { + "access_token": "", + "expires_in": 3600, + "refresh_token": "", + "token_type": "", + "user": { + "email": "", + "firstname": "", + "lastname": "", + "mustchangepassword": "", + "permissions": [ + "endpoints.runscript", + "endpoints.agentupdate", + "endpoints.view", + "" + ], + "roles": [ + "upgradeoperatorrole" + ], + "userid": 2, + "username": "" } - ] - }, - { - "surface": "core-businessunits", - "endpoints": [ + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/auth/logout", + "auth": "jwt", + "params": "body: JSON (fields not yet documented)", + "purpose": "Logout user (for frontend token cleanup).", + "example": "curl -X POST http://localhost:5001/api/auth/logout -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "GET", + "path": "/api/auth/me", + "auth": "jwt", + "params": "not documented", + "purpose": "Get current authenticated user info.", + "example": "curl http://localhost:5001/api/auth/me -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "email": "", + "firstname": "", + "lastname": "", + "mustchangepassword": "", + "permissions": [ + "assets.view", + "assets.create", + "assets.edit", + "" + ], + "roles": [ + "admin" + ], + "userid": 1, + "username": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/auth/refresh", + "auth": "jwt (refresh token)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Refresh access token using refresh token.", + "example": "curl -X POST http://localhost:5001/api/auth/refresh -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + } + ] + }, + { + "surface": "core-businessunits", + "endpoints": [ + { + "method": "GET", + "path": "/api/businessunits", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "List all business units.", + "example": "curl http://localhost:5001/api/businessunits -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "businessunit", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/businessunits", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new business unit.", + "example": "curl -X POST http://localhost:5001/api/businessunits -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/businessunits/", + "auth": "jwt + role:admin", + "params": "path: bu_id (int)", + "purpose": "Delete (deactivate) a business unit.", + "example": "curl -X DELETE http://localhost:5001/api/businessunits/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/businessunits/", + "auth": "permission:assets.view", + "params": "path: bu_id (int)", + "purpose": "Get a single business unit.", + "example": "curl http://localhost:5001/api/businessunits/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/businessunits/", + "auth": "jwt + role:admin", + "params": "path: bu_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a business unit.", + "example": "curl -X PUT http://localhost:5001/api/businessunits/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "core-collector", + "endpoints": [ + { + "method": "POST", + "path": "/api/collector/", + "auth": "api-key (per-plugin collector token)", + "params": "path: pluginname (string); body: JSON (fields not yet documented)", + "purpose": "Generic collector ingest for any plugin (ADR-006).", + "example": "curl -X POST http://localhost:5001/api/collector/x -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "hostname": "", + "queues": [ { - "method": "GET", - "path": "/api/businessunits", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "List all business units.", - "example": "curl http://localhost:5001/api/businessunits -H \"Authorization: Bearer $TOK\"" + "drivername": "HP Universal Printing PS", + "isdefault": true, + "portaddress": "", + "portname": "IP_10.20.0.11", + "queuename": "PRINTER-A" }, { - "method": "POST", - "path": "/api/businessunits", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new business unit.", - "example": "curl -X POST http://localhost:5001/api/businessunits -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "drivername": "HP Universal Printing PS", + "isdefault": false, + "portaddress": "", + "portname": "IP_10.20.0.12", + "queuename": "PRINTER-B" }, { - "method": "DELETE", - "path": "/api/businessunits/", - "auth": "jwt + role:admin", - "params": "path: bu_id (int)", - "purpose": "Delete (deactivate) a business unit.", - "example": "curl -X DELETE http://localhost:5001/api/businessunits/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/businessunits/", - "auth": "permission:assets.view", - "params": "path: bu_id (int)", - "purpose": "Get a single business unit.", - "example": "curl http://localhost:5001/api/businessunits/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/businessunits/", - "auth": "jwt + role:admin", - "params": "path: bu_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a business unit.", - "example": "curl -X PUT http://localhost:5001/api/businessunits/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "drivername": "HP Universal Printing PS", + "isdefault": false, + "portaddress": "", + "portname": "IP_10.20.0.99", + "queuename": "Reception Copier" } - ] - }, - { - "surface": "core-collector", - "endpoints": [ + ] + }, + "responseexample": { + "data": { + "accessprotocols": [], + "action": "updated", + "assetid": 2, + "identityvalue": "LEGACYPC", + "machinelinks": [], + "measuringtoollinkcount": 0, + "measuringtoollinks": [], + "partmarkers": [ + { + "assetid": 3, + "assetnumber": "LEGACYPC-PARTMARKER", + "operationassetid": null + } + ], + "printerlinkcount": 0, + "printerlinks": [], + "status": "ok", + "warnings": [ + "mapped ComputerType not found: Shopfloor PC", + "machine number '0615' is this PC's own asset number; marker not filed under an operation. Rename the PC asset to its hostname, or create the operation asset." + ] + }, + "message": "computers collector updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/collector/_schemas", + "auth": "jwt", + "params": "not documented", + "purpose": "List collector schemas for all enabled plugins (JWT-protected).", + "example": "curl http://localhost:5001/api/collector/_schemas -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/collector/apps", + "auth": "api-key (collector token, legacy shared key)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Update installed applications for a PC (matched by hostname).", + "example": "curl -X POST http://localhost:5001/api/collector/apps -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/collector/bulk", + "auth": "api-key (collector token, legacy shared key)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Bulk update multiple PCs at once.", + "example": "curl -X POST http://localhost:5001/api/collector/bulk -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "pcs": [ { - "method": "POST", - "path": "/api/collector/", - "auth": "api-key (per-plugin collector token)", - "params": "path: pluginname (string); body: JSON (fields not yet documented)", - "purpose": "Generic collector ingest for any plugin (ADR-006).", - "example": "curl -X POST http://localhost:5001/api/collector/x -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/collector/_schemas", - "auth": "jwt", - "params": "not documented", - "purpose": "List collector schemas for all enabled plugins (JWT-protected).", - "example": "curl http://localhost:5001/api/collector/_schemas -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/collector/apps", - "auth": "api-key (collector token, legacy shared key)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Update installed applications for a PC (matched by hostname).", - "example": "curl -X POST http://localhost:5001/api/collector/apps -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/collector/bulk", - "auth": "api-key (collector token, legacy shared key)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Bulk update multiple PCs at once.", - "example": "curl -X POST http://localhost:5001/api/collector/bulk -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/collector/heartbeat", - "auth": "api-key (collector token, legacy shared key)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Record PC online status / heartbeat (single or batch).", - "example": "curl -X POST http://localhost:5001/api/collector/heartbeat -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/collector/pc", - "auth": "api-key (collector token, legacy shared key)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Update one PC from the collection script (matched by hostname).", - "example": "curl -X POST http://localhost:5001/api/collector/pc -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/collector/status", - "auth": "api-key (per-plugin collector token)", - "params": "not documented", - "purpose": "Check collector API status.", - "example": "curl http://localhost:5001/api/collector/status -H \"X-API-Key: $KEY\"" + "hostname": "" } - ] - }, - { - "surface": "core-customfields", - "endpoints": [ + ] + }, + "responseexample": { + "data": { + "errors": [], + "notfound": [ + "WJLEG01" + ], + "timestamp": "2026-01-01T00:00:00.000000", + "updated": 0 + }, + "message": "0 PC(s) updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/collector/heartbeat", + "auth": "api-key (collector token, legacy shared key)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Record PC online status / heartbeat (single or batch).", + "example": "curl -X POST http://localhost:5001/api/collector/heartbeat -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "hostname": "" + }, + "responseexample": { + "data": { + "notfound": [ + "WJLEG01" + ], + "timestamp": "2026-01-01T00:00:00.000000", + "updated": 0 + }, + "message": "0 PC(s) heartbeat recorded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/collector/pc", + "auth": "api-key (collector token, legacy shared key)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Update one PC from the collection script (matched by hostname).", + "example": "curl -X POST http://localhost:5001/api/collector/pc -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/collector/status", + "auth": "api-key (per-plugin collector token)", + "params": "not documented", + "purpose": "Check collector API status.", + "example": "curl http://localhost:5001/api/collector/status -H \"X-API-Key: $KEY\"", + "responseexample": { + "data": { + "endpoints": [ + "POST /api/collector/", + "GET /api/collector/_schemas", + "POST /api/collector/pc", + "" + ], + "status": "ok", + "timestamp": "2026-01-01T00:00:00.000000" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-customfields", + "endpoints": [ + { + "method": "GET", + "path": "/api/customfields", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List custom-field definitions. Filter by ?assettypeid=. ?active=false includes inactive ones.", + "example": "curl http://localhost:5001/api/customfields -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "assettypeid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/customfields", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: customfields.create_field has no docstring.", + "example": "curl -X POST http://localhost:5001/api/customfields -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/customfields/", + "auth": "jwt + role:admin", + "params": "path: fieldid (int)", + "purpose": "UNDOCUMENTED: customfields.delete_field has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/customfields/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/customfields/", + "auth": "jwt + role:admin", + "params": "path: fieldid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: customfields.update_field has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/customfields/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/customfields/asset/", + "auth": "permission:assets.view", + "params": "path: assetid (int)", + "purpose": "Active custom fields for an asset's type, merged with its values.", + "example": "curl http://localhost:5001/api/customfields/asset/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/customfields/asset/", + "auth": "jwt + role:admin", + "params": "path: assetid (int); body: JSON (fields not yet documented)", + "purpose": "Upsert values for an asset. Body: {values: {fieldid: value, ...}}.", + "example": "curl -X PUT http://localhost:5001/api/customfields/asset/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "core-dashboard", + "endpoints": [ + { + "method": "GET", + "path": "/api/dashboard", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Get dashboard summary data (asset-based).", + "example": "curl http://localhost:5001/api/dashboard -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "activeassets": 14, + "bystatus": { + "In Use": 14 + }, + "counts": { + "machines": 0, + "measuringtools": 14, + "networkdevices": 0, + "pcs": 0, + "printers": 0, + "total": 14 + }, + "countsactiveonly": true, + "dualpathcollapsed": true, + "inactiveexcluded": 0, + "inrepair": 0, + "recent": [ + { + "assetid": 14, + "assetnumber": "MT-MAP-TD", + "assettype": "measuring_tool", + "createddate": "2026-01-01T00:00:00.000000Z" + }, + { + "assetid": 13, + "assetnumber": "MT-MAP-MIC", + "assettype": "measuring_tool", + "createddate": "2026-01-01T00:00:00.000000Z" + }, + { + "assetid": 12, + "assetnumber": "MT-MAP-CAL", + "assettype": "measuring_tool", + "createddate": "2026-01-01T00:00:00.000000Z" + }, + "" + ], + "statuses": { + "In Use": 14 + }, + "totalassets": 14, + "totalmachines": 0, + "totalmeasuringtool": 14, + "totalnetwork": 0, + "totalpc": 0, + "totalprinter": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/dashboard/capabilities", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "What THIS caller can reach, for chrome that would otherwise only 401.", + "example": "curl http://localhost:5001/api/dashboard/capabilities -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "cansearch": false + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/dashboard/health", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "Health check endpoint (no auth required).", + "example": "curl http://localhost:5001/api/dashboard/health", + "responseexample": { + "data": { + "database": "healthy", + "status": "ok" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/dashboard/navigation", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "Get navigation items from all loaded plugins.", + "example": "curl http://localhost:5001/api/dashboard/navigation -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/customfields", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List custom-field definitions. Filter by ?assettypeid=. ?active=false includes inactive ones.", - "example": "curl http://localhost:5001/api/customfields -H \"Authorization: Bearer $TOK\"" + "icon": "layout-dashboard", + "name": "Dashboard", + "permission": "assets.view", + "position": 0, + "route": "/" }, { - "method": "POST", - "path": "/api/customfields", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: customfields.create_field has no docstring.", - "example": "curl -X POST http://localhost:5001/api/customfields -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "icon": "map", + "name": "Map", + "permission": "assets.view", + "position": 4, + "route": "/map" }, { - "method": "DELETE", - "path": "/api/customfields/", - "auth": "jwt + role:admin", - "params": "path: fieldid (int)", - "purpose": "UNDOCUMENTED: customfields.delete_field has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/customfields/1 -H \"Authorization: Bearer $TOK\"" + "icon": "bell", + "name": "Notifications", + "permission": "notifications.view", + "plugin": "notifications", + "position": 5, + "route": "/notifications" + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/dashboard/stats", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Get detailed statistics by asset type.", + "example": "curl http://localhost:5001/api/dashboard/stats -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "bytype": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/dashboard/summary", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Get dashboard summary data (asset-based).", + "example": "curl http://localhost:5001/api/dashboard/summary -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "activeassets": 0, + "bystatus": {}, + "counts": { + "machines": 0, + "measuringtools": 0, + "networkdevices": 0, + "pcs": 0, + "printers": 0, + "total": 0 + }, + "countsactiveonly": true, + "dualpathcollapsed": true, + "inactiveexcluded": 0, + "inrepair": 0, + "recent": [], + "statuses": {}, + "totalassets": 0, + "totalmachines": 0, + "totalmeasuringtool": 0, + "totalnetwork": 0, + "totalpc": 0, + "totalprinter": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/dashboard/widgets", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Aggregate dashboard widget definitions from all enabled plugins.", + "example": "curl http://localhost:5001/api/dashboard/widgets -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ + { + "empty": "hide", + "endpoint": "/api/geenforce/dashboard/failures", + "id": "geenforce-failures", + "map": { + "detail": "entryname", + "link": "/pcs/{computerid}", + "meta": [ + { + "key": "message" + }, + { + "key": "exitcode", + "label": "exit" + } + ], + "timestamp": "receivedat", + "title": "hostname" + }, + "permission": "geenforce.manage", + "plugin": "geenforce", + "position": 10, + "render": "exceptions", + "severity": "critical", + "shortname": "Enforcement", + "title": "Enforcement failures", + "viewall": "/geenforce" }, { - "method": "PUT", - "path": "/api/customfields/", - "auth": "jwt + role:admin", - "params": "path: fieldid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: customfields.update_field has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/customfields/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "empty": "hide", + "endpoint": "/api/computers/dashboard/sharedmachines", + "id": "computers-sharedmachines", + "map": { + "detail": "pcs", + "link": "/machines/{assetid}", + "meta": [ + { + "key": "pccount", + "suffix": " PCs" + } + ], + "title": "machinenumber" + }, + "permission": "computers.view", + "plugin": "computers", + "position": 15, + "render": "exceptions", + "severity": "critical", + "shortname": "Duplicate machine no.", + "title": "Machine numbers on two PCs", + "viewall": "/machines" }, { - "method": "GET", - "path": "/api/customfields/asset/", - "auth": "permission:assets.view", - "params": "path: assetid (int)", - "purpose": "Active custom fields for an asset's type, merged with its values.", - "example": "curl http://localhost:5001/api/customfields/asset/1 -H \"Authorization: Bearer $TOK\"" + "empty": "hide", + "endpoint": "/api/endpoints/dashboard/stability", + "id": "endpoints-stability", + "map": { + "detail": "", + "link": "/pcs/{computerid}", + "meta": [ + { + "key": "eventcount", + "suffix": " events (48h)" + } + ], + "title": "hostname" + }, + "permission": "endpoints.fleet", + "plugin": "endpoints", + "position": 16, + "render": "exceptions", + "severity": "critical", + "shortname": "Crashes", + "title": "Endpoints with crashes or shutdowns", + "viewall": "/pcs" }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-dashboarddefaults", + "endpoints": [ + { + "method": "GET", + "path": "/api/dashboarddefaults", + "auth": "permission:settings.view", + "params": "not documented", + "purpose": "List all visitor-IP -> business-unit mappings.", + "example": "curl http://localhost:5001/api/dashboarddefaults -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/dashboarddefaults", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a visitor-IP -> business-unit mapping.", + "example": "curl -X POST http://localhost:5001/api/dashboarddefaults -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "businessunitid": 1, + "description": "Materials lobby kiosk", + "ipaddress": "" + }, + "responseexample": { + "data": { + "businessunit": "Materials", + "businessunitid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "dashboarddefaultid": 1, + "description": "Materials lobby kiosk", + "displaypath": "/shopfloor", + "displayrole": "Dashboard", + "fqdn": "", + "ipaddress": "", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z" + }, + "message": "Mapping created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/dashboarddefaults/", + "auth": "jwt + role:admin", + "params": "path: default_id (int)", + "purpose": "Delete (deactivate) a mapping.", + "example": "curl -X DELETE http://localhost:5001/api/dashboarddefaults/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Mapping deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/dashboarddefaults/", + "auth": "jwt + role:admin", + "params": "path: default_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a mapping.", + "example": "curl -X PUT http://localhost:5001/api/dashboarddefaults/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "description": "moved" + }, + "responseexample": { + "data": { + "businessunit": "Materials", + "businessunitid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "dashboarddefaultid": 1, + "description": "moved", + "displaypath": "/shopfloor", + "displayrole": "Dashboard", + "fqdn": "", + "ipaddress": "", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z" + }, + "message": "Mapping updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/dashboarddefaults/display-role", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "Resolve what a single 'display' PC should show, from its own IP.", + "example": "curl http://localhost:5001/api/dashboarddefaults/display-role", + "queryparams": [ + { + "name": "fqdn", + "type": "string", + "required": false + }, + { + "name": "ipaddress", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "businessunit": null, + "businessunitid": null, + "fqdn": "", + "ipaddress": "", + "path": "/parts-kiosk", + "role": "3DPrintRoom" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/dashboarddefaults/visitor-location", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "Resolve the business unit for the calling display by its IP.", + "example": "curl http://localhost:5001/api/dashboarddefaults/visitor-location", + "queryparams": [ + { + "name": "fqdn", + "type": "string", + "required": false + }, + { + "name": "ipaddress", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "businessunit": "Materials", + "businessunitid": 1, + "fqdn": "", + "ipaddress": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-docs", + "endpoints": [ + { + "method": "GET", + "path": "/api/docs/", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "Redoc page. url_for keeps the asset URLs correct under any mount.", + "example": "curl http://localhost:5001/api/docs/" + }, + { + "method": "GET", + "path": "/api/docs/llms.txt", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "Concise LLM-oriented API guide.", + "example": "curl http://localhost:5001/api/docs/llms.txt" + }, + { + "method": "GET", + "path": "/api/docs/openapi.json", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "The generated OpenAPI 3.1 spec (machine + LLM readable).", + "example": "curl http://localhost:5001/api/docs/openapi.json" + }, + { + "method": "GET", + "path": "/api/docs/redoc.standalone.js", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "Vendored Redoc bundle (offline).", + "example": "curl http://localhost:5001/api/docs/redoc.standalone.js" + } + ] + }, + { + "surface": "core-locations", + "endpoints": [ + { + "method": "GET", + "path": "/api/locations", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all locations.", + "example": "curl http://localhost:5001/api/locations -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "locationname", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/locations", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new location.", + "example": "curl -X POST http://localhost:5001/api/locations -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/locations/", + "auth": "jwt + role:admin", + "params": "path: location_id (int)", + "purpose": "Delete (deactivate) a location.", + "example": "curl -X DELETE http://localhost:5001/api/locations/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/locations/", + "auth": "permission:assets.view", + "params": "path: location_id (int)", + "purpose": "Get a single location.", + "example": "curl http://localhost:5001/api/locations/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/locations/", + "auth": "jwt + role:admin", + "params": "path: location_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a location.", + "example": "curl -X PUT http://localhost:5001/api/locations/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/locations/types", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List location types. ?active=false includes inactive ones.", + "example": "curl http://localhost:5001/api/locations/types -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + } + ], + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/locations/types", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: locations.create_location_type has no docstring.", + "example": "curl -X POST http://localhost:5001/api/locations/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/locations/types/", + "auth": "jwt + role:admin", + "params": "path: type_id (int)", + "purpose": "UNDOCUMENTED: locations.delete_location_type has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/locations/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/locations/types/", + "auth": "jwt + role:admin", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: locations.update_location_type has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/locations/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "core-maplevels", + "endpoints": [ + { + "method": "GET", + "path": "/api/maplevels", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "Every active level, grouped by building, in display order.", + "example": "curl http://localhost:5001/api/maplevels -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "buildings": [ + { + "buildingid": 1, + "buildingname": "Public Works", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "levels": [ + { + "assetcount": 0, + "blueprintdark": null, + "blueprintlight": "floorplan.svg", + "buildingid": 1, + "buildingname": "Public Works", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "isdefault": false, + "levelid": 1, + "levelname": "Ground", + "mapheight": 2550, + "mapwidth": 3300, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "sortorder": 1 + } + ], + "modifieddate": "2026-01-01T00:00:00.000000Z", + "sortorder": 1 + } + ], + "defaultlevelid": 1, + "totalplaced": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/maplevels", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: maplevels.create_level has no docstring.", + "example": "curl -X POST http://localhost:5001/api/maplevels -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/maplevels/", + "auth": "jwt + role:admin", + "params": "path: levelid (int)", + "purpose": "Deactivate a level, refusing while assets are still placed on it.", + "example": "curl -X DELETE http://localhost:5001/api/maplevels/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/maplevels/", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "path: levelid (int)", + "purpose": "UNDOCUMENTED: maplevels.get_level has no docstring.", + "example": "curl http://localhost:5001/api/maplevels/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "blueprintdark": null, + "blueprintlight": "floorplan.svg", + "buildingid": 1, + "buildingname": "Public Works", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "isdefault": false, + "levelid": 1, + "levelname": "Ground", + "mapheight": 2550, + "mapwidth": 3300, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "sortorder": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PATCH|PUT", + "path": "/api/maplevels/", + "auth": "jwt + role:admin", + "params": "path: levelid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: maplevels.update_level has no docstring.", + "example": "curl -X PATCH http://localhost:5001/api/maplevels/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/maplevels//blueprint", + "auth": "jwt + role:admin", + "params": "path: levelid (int); body: JSON (fields not yet documented)", + "purpose": "Upload this level's blueprint for one theme.", + "example": "curl -X POST http://localhost:5001/api/maplevels/1/blueprint -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/maplevels//blueprint/", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "path: levelid (int), filename (path)", + "purpose": "Serve a level's blueprint image. Public, for the same reason as above.", + "example": "curl http://localhost:5001/api/maplevels/1/blueprint/example.png -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/maplevels/buildings", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: maplevels.create_building has no docstring.", + "example": "curl -X POST http://localhost:5001/api/maplevels/buildings -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "PATCH|PUT", + "path": "/api/maplevels/buildings/", + "auth": "jwt + role:admin", + "params": "path: buildingid (int); body: JSON (fields not yet documented)", + "purpose": "Rename or reorder a building. Levels move with it; nothing repositions.", + "example": "curl -X PATCH http://localhost:5001/api/maplevels/buildings/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "core-mappositions", + "endpoints": [ + { + "method": "POST", + "path": "/api/mappositions/positions", + "auth": "permission:assets.edit", + "params": "body: JSON (fields not yet documented)", + "purpose": "Set positions for many assets at once.", + "example": "curl -X POST http://localhost:5001/api/mappositions/positions -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "positions": [ { - "method": "PUT", - "path": "/api/customfields/asset/", - "auth": "jwt + role:admin", - "params": "path: assetid (int); body: JSON (fields not yet documented)", - "purpose": "Upsert values for an asset. Body: {values: {fieldid: value, ...}}.", - "example": "curl -X PUT http://localhost:5001/api/customfields/asset/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "assetid": 1, + "levelid": 2, + "mapx": 42, + "mapy": 43 } - ] - }, - { - "surface": "core-dashboard", - "endpoints": [ + ] + }, + "responseexample": { + "data": { + "snapshotid": 1, + "updated": 1 + }, + "message": "1 position(s) saved", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/mappositions/snapshots", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Snapshots, newest first. Metadata only - the positions are large.", + "example": "curl http://localhost:5001/api/mappositions/snapshots -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/mappositions/snapshots//restore", + "auth": "permission:assets.edit", + "params": "path: snapshotid (int); body: JSON (fields not yet documented)", + "purpose": "Put the positions in this snapshot back.", + "example": "curl -X POST http://localhost:5001/api/mappositions/snapshots/1/restore -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "restored": 3, + "skippedassetids": [] + }, + "message": "3 marker(s) restored", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/mappositions/transform", + "auth": "permission:assets.edit", + "params": "body: JSON (fields not yet documented)", + "purpose": "Move every placed marker on a level by a transform read off landmarks.", + "example": "curl -X POST http://localhost:5001/api/mappositions/transform -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "dryrun": false, + "landmarks": [ { - "method": "GET", - "path": "/api/dashboard", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Get dashboard summary data (asset-based).", - "example": "curl http://localhost:5001/api/dashboard -H \"Authorization: Bearer $TOK\"" + "fromx": 0, + "fromy": 0, + "tox": 0, + "toy": 1450 }, { - "method": "GET", - "path": "/api/dashboard/capabilities", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "What THIS caller can reach, for chrome that would otherwise only 401.", - "example": "curl http://localhost:5001/api/dashboard/capabilities -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/dashboard/health", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "Health check endpoint (no auth required).", - "example": "curl http://localhost:5001/api/dashboard/health" - }, - { - "method": "GET", - "path": "/api/dashboard/navigation", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "Get navigation items from all loaded plugins.", - "example": "curl http://localhost:5001/api/dashboard/navigation -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/dashboard/stats", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Get detailed statistics by asset type.", - "example": "curl http://localhost:5001/api/dashboard/stats -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/dashboard/summary", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Get dashboard summary data (asset-based).", - "example": "curl http://localhost:5001/api/dashboard/summary -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/dashboard/widgets", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Aggregate dashboard widget definitions from all enabled plugins.", - "example": "curl http://localhost:5001/api/dashboard/widgets -H \"Authorization: Bearer $TOK\"" + "fromx": 1000, + "fromy": 1000, + "tox": 1000, + "toy": 2450 } - ] - }, - { - "surface": "core-dashboarddefaults", - "endpoints": [ - { - "method": "GET", - "path": "/api/dashboarddefaults", - "auth": "permission:settings.view", - "params": "not documented", - "purpose": "List all visitor-IP -> business-unit mappings.", - "example": "curl http://localhost:5001/api/dashboarddefaults -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/dashboarddefaults", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a visitor-IP -> business-unit mapping.", - "example": "curl -X POST http://localhost:5001/api/dashboarddefaults -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/dashboarddefaults/", - "auth": "jwt + role:admin", - "params": "path: default_id (int)", - "purpose": "Delete (deactivate) a mapping.", - "example": "curl -X DELETE http://localhost:5001/api/dashboarddefaults/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/dashboarddefaults/", - "auth": "jwt + role:admin", - "params": "path: default_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a mapping.", - "example": "curl -X PUT http://localhost:5001/api/dashboarddefaults/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/dashboarddefaults/display-role", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "Resolve what a single 'display' PC should show, from its own IP.", - "example": "curl http://localhost:5001/api/dashboarddefaults/display-role" - }, - { - "method": "GET", - "path": "/api/dashboarddefaults/visitor-location", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "Resolve the business unit for the calling display by its IP.", - "example": "curl http://localhost:5001/api/dashboarddefaults/visitor-location" + ], + "levelid": 1 + }, + "responseexample": { + "data": { + "assetcount": 3, + "dryrun": false, + "levelid": 1, + "moves": [ + { + "assetid": 1, + "assetnumber": "M000", + "fromx": 100, + "fromy": 100, + "name": null, + "outofbounds": false, + "tox": 100, + "toy": 1550 + }, + { + "assetid": 2, + "assetnumber": "M001", + "fromx": 1500, + "fromy": 1200, + "name": null, + "outofbounds": true, + "tox": 1500, + "toy": 2650 + }, + { + "assetid": 3, + "assetnumber": "M002", + "fromx": 3200, + "fromy": 2500, + "name": null, + "outofbounds": true, + "tox": 3200, + "toy": 3950 + } + ], + "outofboundscount": 2, + "snapshotid": 1, + "tolevelid": 1, + "transform": { + "offsetx": 0.0, + "offsety": 1450.0, + "scalex": 1.0, + "scaley": 1.0 } - ] - }, - { - "surface": "core-docs", - "endpoints": [ + }, + "message": "3 marker(s) moved; snapshot 1 can restore them", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/mappositions/verify", + "auth": "permission:assets.edit", + "params": "body: JSON (fields not yet documented)", + "purpose": "Mark markers as reviewed against the current drawing without moving them.", + "example": "curl -X POST http://localhost:5001/api/mappositions/verify -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "assetids": [ + 1 + ], + "unverify": true + }, + "responseexample": { + "data": { + "updated": 1 + }, + "message": "1 marker(s) unverified", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + } + ] + }, + { + "surface": "core-models", + "endpoints": [ + { + "method": "GET", + "path": "/api/models", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all vendor catalog models.", + "example": "curl http://localhost:5001/api/models -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "category", + "type": "string", + "required": false + }, + { + "name": "modelnumber", + "type": "string", + "required": false + }, + { + "name": "modeltype", + "type": "integer", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "vendor", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/models", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new model.", + "example": "curl -X POST http://localhost:5001/api/models -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/models/", + "auth": "jwt + role:admin", + "params": "path: model_id (int)", + "purpose": "Delete (deactivate) a model.", + "example": "curl -X DELETE http://localhost:5001/api/models/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/models/", + "auth": "permission:assets.view", + "params": "path: model_id (int)", + "purpose": "Get a single model.", + "example": "curl http://localhost:5001/api/models/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/models/", + "auth": "jwt + role:admin", + "params": "path: model_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a model.", + "example": "curl -X PUT http://localhost:5001/api/models/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/models//image", + "auth": "jwt + role:admin", + "params": "path: model_id (int)", + "purpose": "Clear a model image and delete the uploaded file if we own it.", + "example": "curl -X DELETE http://localhost:5001/api/models/1/image -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "documentationurl": null, + "imageurl": null, + "isactive": true, + "modelnumber": "TESTMODEL-1", + "modelnumberid": 1, + "modeltypeid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "vendorid": null + }, + "message": "Model image removed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/models//image", + "auth": "jwt + role:admin", + "params": "path: model_id (int); body: JSON (fields not yet documented)", + "purpose": "Upload (or replace) the photo for a model.", + "example": "curl -X POST http://localhost:5001/api/models/1/image -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "documentationurl": null, + "imageurl": "/api/models/image/model-1.jpg", + "isactive": true, + "modelnumber": "TESTMODEL-1", + "modelnumberid": 1, + "modeltypeid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "vendorid": null + }, + "message": "Model image uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/models/image/", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "path: filename (path)", + "purpose": "Serve an uploaded model image (public - asset detail pages read it).", + "example": "curl http://localhost:5001/api/models/image/example.png" + } + ] + }, + { + "surface": "core-modeltypes", + "endpoints": [ + { + "method": "GET", + "path": "/api/modeltypes", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all model types with optional filtering.", + "example": "curl http://localhost:5001/api/modeltypes -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "category", + "type": "string", + "required": false + }, + { + "name": "modeltype", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/modeltypes", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new model type.", + "example": "curl -X POST http://localhost:5001/api/modeltypes -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/modeltypes/", + "auth": "jwt + role:admin", + "params": "path: type_id (int)", + "purpose": "Delete (deactivate) a model type.", + "example": "curl -X DELETE http://localhost:5001/api/modeltypes/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/modeltypes/", + "auth": "permission:assets.view", + "params": "path: type_id (int)", + "purpose": "Get a single model type.", + "example": "curl http://localhost:5001/api/modeltypes/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/modeltypes/", + "auth": "jwt + role:admin", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a model type.", + "example": "curl -X PUT http://localhost:5001/api/modeltypes/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "core-operatingsystems", + "endpoints": [ + { + "method": "GET", + "path": "/api/operatingsystems", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all operating systems.", + "example": "curl http://localhost:5001/api/operatingsystems -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "osname", + "type": "string", + "required": false + }, + { + "name": "osversion", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/operatingsystems", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new operating system.", + "example": "curl -X POST http://localhost:5001/api/operatingsystems -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/operatingsystems/", + "auth": "jwt + role:admin", + "params": "path: os_id (int)", + "purpose": "Delete (deactivate) an operating system.", + "example": "curl -X DELETE http://localhost:5001/api/operatingsystems/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/operatingsystems/", + "auth": "permission:assets.view", + "params": "path: os_id (int)", + "purpose": "Get a single operating system.", + "example": "curl http://localhost:5001/api/operatingsystems/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/operatingsystems/", + "auth": "jwt + role:admin", + "params": "path: os_id (int); body: JSON (fields not yet documented)", + "purpose": "Update an operating system.", + "example": "curl -X PUT http://localhost:5001/api/operatingsystems/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "core-plugins", + "endpoints": [ + { + "method": "GET", + "path": "/api/plugins", + "auth": "permission:settings.view", + "params": "not documented", + "purpose": "List all discovered plugins (enabled or not) with their metadata and the framework contract version.", + "example": "curl http://localhost:5001/api/plugins -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/plugins/", + "auth": "jwt + role:admin", + "params": "path: name (string); body: JSON (fields not yet documented)", + "purpose": "Enable or disable a plugin. Takes effect on the next app restart for route/navigation changes.", + "example": "curl -X PUT http://localhost:5001/api/plugins/x -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/plugins/enabled", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "Return just the names of enabled plugins as a flat array.", + "example": "curl http://localhost:5001/api/plugins/enabled -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ + "backups", + "computers", + "employees", + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/plugins/settings-routes", + "auth": "permission:settings.view", + "params": "not documented", + "purpose": "Return settings routes contributed by all enabled plugins.", + "example": "curl http://localhost:5001/api/plugins/settings-routes -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "routes": [ + { + "component": "drawn.vue", + "hub": "model-catalog", + "name": "drawn-route", + "path": "drawn", + "tab": "Drawn" + }, + { + "component": ".plugins-staged/computers/views/OperatingSystemsList.vue", + "hub": "model-catalog", + "name": "model-catalog-os", + "path": "operatingsystems", + "tab": "Operating Systems" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-pluginui", + "endpoints": [ + { + "method": "GET", + "path": "/api/pluginui/asset-panels", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Return the asset-detail panels matching one asset's type (get_asset_panels).", + "example": "curl http://localhost:5001/api/pluginui/asset-panels -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "assetid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/docs/", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "Redoc page. url_for keeps the asset URLs correct under any mount.", - "example": "curl http://localhost:5001/api/docs/" + "assettypes": [ + "computer" + ], + "empty": "No agent report yet.", + "endpoint": "/api/endpoints/asset/{assetid}/status", + "group": "details", + "id": "endpoints-status", + "plugin": "endpoints", + "position": 10, + "render": "keyvalue", + "title": "Endpoint status" }, { - "method": "GET", - "path": "/api/docs/llms.txt", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "Concise LLM-oriented API guide.", - "example": "curl http://localhost:5001/api/docs/llms.txt" + "assettypes": [ + "computer" + ], + "collapsible": true, + "commandendpoint": "/api/endpoints/{assetid}/commands", + "empty": "No monitored services reported.", + "endpoint": "/api/endpoints/asset/{assetid}/services", + "facets": { + "key": "statelabel", + "order": [ + "Running", + "Stopped", + "Paused", + "" + ] + }, + "filter": { + "equals": "service", + "key": "kind" + }, + "group": "serviceprocess", + "id": "endpoints-tracked-services", + "map": { + "action": "action", + "badge": { + "color": "statecolor", + "label": "statelabel" + }, + "title": "name" + }, + "permission": "endpoints.command", + "plugin": "endpoints", + "position": 12, + "render": "list", + "status": { + "key": "statecolor", + "levels": { + "green": "ok", + "red": "critical", + "yellow": "warning" + } + }, + "title": "Tracked Services" }, { - "method": "GET", - "path": "/api/docs/openapi.json", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "The generated OpenAPI 3.1 spec (machine + LLM readable).", - "example": "curl http://localhost:5001/api/docs/openapi.json" + "assettypes": [ + "computer" + ], + "collapsible": true, + "commandendpoint": "/api/endpoints/{assetid}/commands", + "empty": "No monitored processes reported.", + "endpoint": "/api/endpoints/asset/{assetid}/services", + "facets": { + "key": "statelabel", + "order": [ + "Running", + "Stopped", + "Paused", + "" + ] + }, + "filter": { + "equals": "process", + "key": "kind" + }, + "group": "serviceprocess", + "id": "endpoints-tracked-processes", + "map": { + "action": "action", + "badge": { + "color": "statecolor", + "label": "statelabel" + }, + "title": "name" + }, + "permission": "endpoints.command", + "plugin": "endpoints", + "position": 13, + "render": "list", + "status": { + "key": "statecolor", + "levels": { + "green": "ok", + "red": "critical", + "yellow": "warning" + } + }, + "title": "Tracked Processes" }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/pluginui/asset-presentation", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Merge enabled plugins' asset-type presentation entries (hook).", + "example": "curl http://localhost:5001/api/pluginui/asset-presentation -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/docs/redoc.standalone.js", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "Vendored Redoc bundle (offline).", - "example": "curl http://localhost:5001/api/docs/redoc.standalone.js" + "assettype": "measuring_tool", + "icon": "ruler", + "label": "Measuring Tool", + "plugin": "measuringtools", + "route": "/measuringtools/by-asset/{assetid}" } - ] - }, - { - "surface": "core-locations", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/pluginui/asset-type-descriptors", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Merge enabled plugins' asset-type subtype descriptors.", + "example": "curl http://localhost:5001/api/pluginui/asset-type-descriptors -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/locations", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all locations.", - "example": "curl http://localhost:5001/api/locations -H \"Authorization: Bearer $TOK\"" + "assettype": "computer", + "edit_permission": "computers.manage", + "optional_tabs": [], + "plugin": "computers", + "subtype_color_field": "color", + "subtype_description_field": "description", + "subtype_endpoint": "/computers/types", + "subtype_id_field": "computertypeid", + "subtype_label_field": "computertype" }, { - "method": "POST", - "path": "/api/locations", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new location.", - "example": "curl -X POST http://localhost:5001/api/locations -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "assettype": "machine", + "edit_permission": "machines.manage", + "optional_tabs": [], + "plugin": "machines", + "subtype_color_field": "color", + "subtype_description_field": "description", + "subtype_endpoint": "/machines/types", + "subtype_id_field": "machinetypeid", + "subtype_label_field": "machinetype" }, { - "method": "DELETE", - "path": "/api/locations/", - "auth": "jwt + role:admin", - "params": "path: location_id (int)", - "purpose": "Delete (deactivate) a location.", - "example": "curl -X DELETE http://localhost:5001/api/locations/1 -H \"Authorization: Bearer $TOK\"" + "assettype": "measuring_tool", + "edit_permission": "measuringtools.manage", + "optional_tabs": [], + "plugin": "measuringtools", + "subtype_color_field": "color", + "subtype_description_field": "description", + "subtype_endpoint": "/measuringtools/types", + "subtype_id_field": "measuringtooltypeid", + "subtype_label_field": "name" + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/pluginui/core-type-descriptors", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Return type descriptors for core-owned non-asset types.", + "example": "curl http://localhost:5001/api/pluginui/core-type-descriptors -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ + { + "category": "location", + "edit_permission": "admin", + "group": "other", + "optional_tabs": [], + "subtype_color_field": "color", + "subtype_description_field": "description", + "subtype_endpoint": "/locations/types", + "subtype_id_field": "locationtypeid", + "subtype_label_field": "locationtype", + "type_name": "Location Type", + "type_name_plural": "Location Types" }, { - "method": "GET", - "path": "/api/locations/", - "auth": "permission:assets.view", - "params": "path: location_id (int)", - "purpose": "Get a single location.", - "example": "curl http://localhost:5001/api/locations/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/locations/", - "auth": "jwt + role:admin", - "params": "path: location_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a location.", - "example": "curl -X PUT http://localhost:5001/api/locations/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/locations/types", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List location types. ?active=false includes inactive ones.", - "example": "curl http://localhost:5001/api/locations/types -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/locations/types", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: locations.create_location_type has no docstring.", - "example": "curl -X POST http://localhost:5001/api/locations/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/locations/types/", - "auth": "jwt + role:admin", - "params": "path: type_id (int)", - "purpose": "UNDOCUMENTED: locations.delete_location_type has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/locations/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/locations/types/", - "auth": "jwt + role:admin", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: locations.update_location_type has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/locations/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "category": "notification", + "custom_component": "NotificationTypesTab", + "edit_permission": "admin", + "group": "other", + "optional_tabs": [], + "subtype_color_field": "typecolor", + "subtype_description_field": "typedescription", + "subtype_endpoint": "/notifications/types", + "subtype_id_field": "notificationtypeid", + "subtype_label_field": "typename", + "type_name": "Notification Type", + "type_name_plural": "Notification Types" } - ] - }, - { - "surface": "core-maplevels", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/pluginui/map-overlays", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Merge enabled plugins' map overlay declarations (get_map_overlays hook).", + "example": "curl http://localhost:5001/api/pluginui/map-overlays -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/maplevels", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "Every active level, grouped by building, in display order.", - "example": "curl http://localhost:5001/api/maplevels -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/maplevels", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: maplevels.create_level has no docstring.", - "example": "curl -X POST http://localhost:5001/api/maplevels -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/maplevels/", - "auth": "jwt + role:admin", - "params": "path: levelid (int)", - "purpose": "Deactivate a level, refusing while assets are still placed on it.", - "example": "curl -X DELETE http://localhost:5001/api/maplevels/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/maplevels/", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "path: levelid (int)", - "purpose": "UNDOCUMENTED: maplevels.get_level has no docstring.", - "example": "curl http://localhost:5001/api/maplevels/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PATCH|PUT", - "path": "/api/maplevels/", - "auth": "jwt + role:admin", - "params": "path: levelid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: maplevels.update_level has no docstring.", - "example": "curl -X PATCH http://localhost:5001/api/maplevels/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/maplevels//blueprint", - "auth": "jwt + role:admin", - "params": "path: levelid (int); body: JSON (fields not yet documented)", - "purpose": "Upload this level's blueprint for one theme.", - "example": "curl -X POST http://localhost:5001/api/maplevels/1/blueprint -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/maplevels//blueprint/", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "path: levelid (int), filename (path)", - "purpose": "Serve a level's blueprint image. Public, for the same reason as above.", - "example": "curl http://localhost:5001/api/maplevels/1/blueprint/example.png -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/maplevels/buildings", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: maplevels.create_building has no docstring.", - "example": "curl -X POST http://localhost:5001/api/maplevels/buildings -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "PATCH|PUT", - "path": "/api/maplevels/buildings/", - "auth": "jwt + role:admin", - "params": "path: buildingid (int); body: JSON (fields not yet documented)", - "purpose": "Rename or reorder a building. Levels move with it; nothing repositions.", - "example": "curl -X PATCH http://localhost:5001/api/maplevels/buildings/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "endpoint": "/api/measuringtools/map-overlay", + "id": "calibration-due", + "label": "Calibration due", + "legend": true, + "plugin": "measuringtools", + "style": "badge" } - ] - }, - { - "surface": "core-mappositions", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/pluginui/settings-cards", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Merge enabled plugins' settings-catalog cards (get_settings_cards hook).", + "example": "curl http://localhost:5001/api/pluginui/settings-cards -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "POST", - "path": "/api/mappositions/positions", - "auth": "permission:assets.edit", - "params": "body: JSON (fields not yet documented)", - "purpose": "Set positions for many assets at once.", - "example": "curl -X POST http://localhost:5001/api/mappositions/positions -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "description": "Collection interval, share root for part-marker snapshots, staleness threshold and revision retention", + "group": "Machines", + "icon": "package", + "plugin": "backups", + "position": 21, + "title": "Backups", + "to": "/settings/backups" }, { - "method": "GET", - "path": "/api/mappositions/snapshots", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Snapshots, newest first. Metadata only - the positions are large.", - "example": "curl http://localhost:5001/api/mappositions/snapshots -H \"Authorization: Bearer $TOK\"" + "description": "Download the collector script stamped with this site's URL and ranges", + "group": "Computers", + "icon": "download", + "plugin": "computers", + "position": 26, + "title": "Asset reporter", + "to": "/settings/collector" }, { - "method": "POST", - "path": "/api/mappositions/snapshots//restore", - "auth": "permission:assets.edit", - "params": "path: snapshotid (int); body: JSON (fields not yet documented)", - "purpose": "Put the positions in this snapshot back.", - "example": "curl -X POST http://localhost:5001/api/mappositions/snapshots/1/restore -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "description": "The shared agent key PCs use until they enroll, the site agent installer builder, and what the agent reports.", + "group": "Endpoints", + "icon": "key", + "plugin": "endpoints", + "position": 27, + "title": "Endpoints", + "to": "/settings/endpoints/agentkey" }, - { - "method": "POST", - "path": "/api/mappositions/transform", - "auth": "permission:assets.edit", - "params": "body: JSON (fields not yet documented)", - "purpose": "Move every placed marker on a level by a transform read off landmarks.", - "example": "curl -X POST http://localhost:5001/api/mappositions/transform -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-reports", + "endpoints": [ + { + "method": "GET", + "path": "/api/reports", + "auth": "permission:reports.view", + "params": "not documented", + "purpose": "List all available reports.", + "example": "curl http://localhost:5001/api/reports -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "reports": [ + { + "category": "inventory", + "description": "Machine count grouped by machine type", + "endpoint": "/api/reports/machines-by-type", + "id": "machines-by-type", + "name": "Machines by Type" + }, + { + "category": "inventory", + "description": "Asset count grouped by status", + "endpoint": "/api/reports/assets-by-status", + "id": "assets-by-status", + "name": "Assets by Status" + }, + { + "category": "usage", + "description": "Most clicked knowledge base articles", + "endpoint": "/api/reports/kb-popularity", + "id": "kb-popularity", + "name": "KB Popularity" + }, + "" + ], + "total": 13 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/reports/asset-inventory", + "auth": "permission:reports.view", + "params": "not documented", + "purpose": "Report: Complete asset inventory summary.", + "example": "curl http://localhost:5001/api/reports/asset-inventory -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "format", + "type": "string", + "required": false + }, + { + "name": "locationid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": { + "data": { + "bylocation": [], + "bystatus": [], + "bytype": [] }, + "generated": "2026-01-01T00:00:00.000000", + "report": "asset_inventory", + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/reports/assets-by-status", + "auth": "permission:reports.view", + "params": "not documented", + "purpose": "Report: Asset count grouped by status.", + "example": "curl http://localhost:5001/api/reports/assets-by-status -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "assettypeid", + "type": "integer", + "required": false + }, + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "format", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "data": [], + "generated": "2026-01-01T00:00:00.000000", + "report": "assets_by_status", + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/reports/email", + "auth": "permission:reports.export", + "params": "body: JSON (fields not yet documented)", + "purpose": "Email a report's data as an HTML table (on-demand delivery).", + "example": "curl -X POST http://localhost:5001/api/reports/email -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "columns": [ { - "method": "POST", - "path": "/api/mappositions/verify", - "auth": "permission:assets.edit", - "params": "body: JSON (fields not yet documented)", - "purpose": "Mark markers as reviewed against the current drawing without moving them.", - "example": "curl -X POST http://localhost:5001/api/mappositions/verify -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "key": "vendor", + "label": "Vendor" } - ] - }, - { - "surface": "core-models", - "endpoints": [ + ], + "rows": [ { - "method": "GET", - "path": "/api/models", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all vendor catalog models.", - "example": "curl http://localhost:5001/api/models -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/models", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new model.", - "example": "curl -X POST http://localhost:5001/api/models -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/models/", - "auth": "jwt + role:admin", - "params": "path: model_id (int)", - "purpose": "Delete (deactivate) a model.", - "example": "curl -X DELETE http://localhost:5001/api/models/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/models/", - "auth": "permission:assets.view", - "params": "path: model_id (int)", - "purpose": "Get a single model.", - "example": "curl http://localhost:5001/api/models/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/models/", - "auth": "jwt + role:admin", - "params": "path: model_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a model.", - "example": "curl -X PUT http://localhost:5001/api/models/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/models//image", - "auth": "jwt + role:admin", - "params": "path: model_id (int)", - "purpose": "Clear a model image and delete the uploaded file if we own it.", - "example": "curl -X DELETE http://localhost:5001/api/models/1/image -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/models//image", - "auth": "jwt + role:admin", - "params": "path: model_id (int); body: JSON (fields not yet documented)", - "purpose": "Upload (or replace) the photo for a model.", - "example": "curl -X POST http://localhost:5001/api/models/1/image -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/models/image/", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "path: filename (path)", - "purpose": "Serve an uploaded model image (public - asset detail pages read it).", - "example": "curl http://localhost:5001/api/models/image/example.png" + "vendor": "Dell" } - ] - }, - { - "surface": "core-modeltypes", - "endpoints": [ + ], + "subject": "Warranty Report", + "to": "" + }, + "responseexample": { + "data": { + "reason": "notconfigured", + "sent": false + }, + "message": "Email is not configured (SMTP disabled or host unset).", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/reports/kb-popularity", + "auth": "permission:reports.view", + "params": "not documented", + "purpose": "Report: Most clicked knowledge base articles.", + "example": "curl http://localhost:5001/api/reports/kb-popularity -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "format", + "type": "string", + "required": false + }, + { + "name": "limit", + "type": "integer", + "required": false, + "default": 20 + } + ], + "responseexample": { + "data": { + "data": [], + "generated": "2026-01-01T00:00:00.000000", + "report": "kb_popularity", + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/reports/machines-by-type", + "auth": "permission:reports.view", + "params": "not documented", + "purpose": "Report: Machine count grouped by machine type.", + "example": "curl http://localhost:5001/api/reports/machines-by-type -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "format", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "data": [], + "generated": "2026-01-01T00:00:00.000000", + "report": "machines_by_type", + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/reports/pc-relationships", + "auth": "permission:reports.view", + "params": "not documented", + "purpose": "Report: PCs with relationships to shop floor machines.", + "example": "curl http://localhost:5001/api/reports/pc-relationships -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "format", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "data": [ + { + "hostname": "", + "ip": "", + "machine_number": "4242", + "model": "", + "vendor": "" + } + ], + "generated": "2026-01-01T00:00:00.000000", + "report": "pc_relationships", + "total": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/reports/software-compliance", + "auth": "permission:reports.view", + "params": "not documented", + "purpose": "Report: Required applications vs installed (per PC).", + "example": "curl http://localhost:5001/api/reports/software-compliance -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "appid", + "type": "string", + "required": false + }, + { + "name": "format", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "data": [], + "generated": "2026-01-01T00:00:00.000000", + "message": "No required applications defined", + "report": "software_compliance" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-scripts", + "endpoints": [ + { + "method": "GET", + "path": "/api/scripts", + "auth": "permission:endpoints.runscript", + "params": "not documented", + "purpose": "List scripts (active by default).", + "example": "curl http://localhost:5001/api/scripts -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/scripts", + "auth": "permission:endpoints.runscript", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a script catalog entry (body uploaded separately).", + "example": "curl -X POST http://localhost:5001/api/scripts -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "scriptname": "autologon", + "workingdirectory": "C:\\Program Files\\Sysinternals" + }, + "responseexample": { + "data": { + "captureoutput": false, + "createddate": "2026-01-01T00:00:00.000000Z", + "errormode": "default", + "filename": null, + "hasbody": false, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "runcontext": "system", + "scriptdescription": null, + "scriptid": 1, + "scriptname": "autologon", + "sha256": null, + "workingdirectory": "C:\\Program Files\\Sysinternals" + }, + "message": "Script created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/scripts/", + "auth": "permission:endpoints.runscript", + "params": "path: script_id (int)", + "purpose": "UNDOCUMENTED: scripts.delete_script has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/scripts/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/scripts/", + "auth": "permission:endpoints.runscript", + "params": "path: script_id (int)", + "purpose": "UNDOCUMENTED: scripts.get_script has no docstring.", + "example": "curl http://localhost:5001/api/scripts/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/scripts/", + "auth": "permission:endpoints.runscript", + "params": "path: script_id (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: scripts.update_script has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/scripts/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "scriptdescription": "now documented" + }, + "responseexample": { + "data": { + "captureoutput": true, + "createddate": "2026-01-01T00:00:00.000000Z", + "errormode": "default", + "filename": null, + "hasbody": false, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "runcontext": "system", + "scriptdescription": "now documented", + "scriptid": 1, + "scriptname": "keep-my-flag", + "sha256": null, + "workingdirectory": null + }, + "message": "Script updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/scripts//body", + "auth": "permission:endpoints.runscript", + "params": "path: script_id (int); body: JSON (fields not yet documented)", + "purpose": "Upload (or replace) the .ps1 body for a script.", + "example": "curl -X POST http://localhost:5001/api/scripts/1/body -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "bytes": 23, + "captureoutput": false, + "createddate": "2026-01-01T00:00:00.000000Z", + "errormode": "default", + "filename": "script-1.ps1", + "hasbody": true, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "runcontext": "system", + "scriptdescription": null, + "scriptid": 1, + "scriptname": "digest-check", + "sha256": "", + "uploadedfilename": "digest-check.ps1", + "workingdirectory": null + }, + "message": "Script body uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/scripts/body/", + "auth": "permission:endpoints.runscript", + "params": "path: filename (path)", + "purpose": "Operator-facing script body download (JWT/RBAC).", + "example": "curl http://localhost:5001/api/scripts/body/example.png -H \"Authorization: Bearer $TOK\"" + } + ] + }, + { + "surface": "core-search", + "endpoints": [ + { + "method": "GET", + "path": "/api/search", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "Global search across multiple entity types.", + "example": "curl http://localhost:5001/api/search -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "q", + "type": "string", + "required": false, + "default": "" + } + ], + "responseexample": { + "data": { + "counts": { + "knowledgebase": 2 + }, + "degraded": [ + "Employee" + ], + "query": "zzkeyword", + "results": [ + { + "id": 1, + "linkurl": "u", + "relevance": 25.0, + "subtitle": "Livesearchapp", + "title": "Zzrunbook for the live one", + "type": "knowledgebase", + "url": "/knowledgebase/1" + }, + { + "id": 3, + "linkurl": "u", + "relevance": 25.0, + "subtitle": null, + "title": "Zzrunbook with no topic", + "type": "knowledgebase", + "url": "/knowledgebase/3" + } + ], + "total": 2, + "total_all": 2 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/search/suggest", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "A better spelling for a query that found nothing, or null.", + "example": "curl http://localhost:5001/api/search/suggest -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "q", + "type": "string", + "required": false, + "default": "" + } + ], + "responseexample": { + "data": { + "query": "keyecne", + "suggestion": "keyence" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-settings", + "endpoints": [ + { + "method": "GET", + "path": "/api/settings", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "List all settings, optionally filtered by category.", + "example": "curl http://localhost:5001/api/settings -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "category", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/modeltypes", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all model types with optional filtering.", - "example": "curl http://localhost:5001/api/modeltypes -H \"Authorization: Bearer $TOK\"" + "category": "auth", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "SAML Assertion Consumer Service URL", + "key": "saml_acs_url", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 111, + "value": "", + "valuetype": "string" }, { - "method": "POST", - "path": "/api/modeltypes", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new model type.", - "example": "curl -X POST http://localhost:5001/api/modeltypes -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "category": "auth", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "SAML group name that grants admin role", + "key": "saml_admin_group", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 114, + "value": "", + "valuetype": "string" }, { - "method": "DELETE", - "path": "/api/modeltypes/", - "auth": "jwt + role:admin", - "params": "path: type_id (int)", - "purpose": "Delete (deactivate) a model type.", - "example": "curl -X DELETE http://localhost:5001/api/modeltypes/1 -H \"Authorization: Bearer $TOK\"" + "category": "auth", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Allow local username/password login when SAML is enabled", + "key": "saml_allow_local_login", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 112, + "value": true, + "valuetype": "boolean" }, - { - "method": "GET", - "path": "/api/modeltypes/", - "auth": "permission:assets.view", - "params": "path: type_id (int)", - "purpose": "Get a single model type.", - "example": "curl http://localhost:5001/api/modeltypes/1 -H \"Authorization: Bearer $TOK\"" + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/settings", + "auth": "permission:settings.edit", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new setting (admin only).", + "example": "curl -X POST http://localhost:5001/api/settings -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/settings/", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "path: key (string)", + "purpose": "Get a single setting by key.", + "example": "curl http://localhost:5001/api/settings/x -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "category": "plugin.endpoints", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Accept a one-line install bootstrap token in the ?t= query string as well as the X-Endpoint-Bootstrap-Token header. On (the default) keeps the pasted install commands and the Download .ps1 link workin...", + "key": "plugin.endpoints.bootstrapquerytoken", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 1, + "value": false, + "valuetype": "boolean" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/settings/", + "auth": "permission:settings.edit", + "params": "path: key (string); body: JSON (fields not yet documented)", + "purpose": "Update a setting value.", + "example": "curl -X PUT http://localhost:5001/api/settings/x -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "value": "" + }, + "responseexample": { + "data": { + "category": "plugin.endpoints", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Accept a one-line install bootstrap token in the ?t= query string as well as the X-Endpoint-Bootstrap-Token header. On (the default) keeps the pasted install commands and the Download .ps1 link workin...", + "key": "plugin.endpoints.bootstrapquerytoken", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 1, + "value": false, + "valuetype": "boolean" + }, + "message": "Setting updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/settings/asset-import/import", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Validate uploaded CSVs and, when commit=true, load them.", + "example": "curl -X POST http://localhost:5001/api/settings/asset-import/import -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/settings/asset-import/script", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "Download Collect-ShopDB.ps1 with this site's CSV path embedded.", + "example": "curl http://localhost:5001/api/settings/asset-import/script -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/settings/asset-import/templates", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "List the importable CSV tables in the order they must be uploaded.", + "example": "curl http://localhost:5001/api/settings/asset-import/templates -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "tables": [ + { + "filename": "assetstatuses.csv", + "table": "assetstatuses" + }, + { + "filename": "assettypes.csv", + "table": "assettypes" + }, + { + "filename": "locationtypes.csv", + "table": "locationtypes" + }, + "" + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/settings/asset-import/templates/", + "auth": "jwt + role:admin", + "params": "path: tablename (string)", + "purpose": "Download a generated CSV template for a single importable table.", + "example": "curl http://localhost:5001/api/settings/asset-import/templates/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/settings/asset-import/winc/batches", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "List applied/undone WINC import batches, newest first (for the undo UI).", + "example": "curl http://localhost:5001/api/settings/asset-import/winc/batches -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "batches": [ + { + "batchid": "", + "createdat": "2026-01-01 00:00:00.000000", + "createdby": "", + "kind": "winc-machine-adoption", + "rowcount": 1, + "status": "undone", + "undoneat": "2026-01-01 00:00:00.000000" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/settings/asset-import/winc/commit", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Apply a WINC plan reversibly. Requires acknowledgment for needs-create.", + "example": "curl -X POST http://localhost:5001/api/settings/asset-import/winc/commit -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "batchid": "", + "blocking": false, + "committed": true, + "kind": "winc-machine-adoption", + "needscreate": { + "businessunit": { + "Large Parts": 1 + } }, - { - "method": "PUT", - "path": "/api/modeltypes/", - "auth": "jwt + role:admin", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a model type.", - "example": "curl -X PUT http://localhost:5001/api/modeltypes/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "planhash": "", + "rowcount": 1, + "summary": { + "ambiguous_match": 0, + "businessunit_blank": 0, + "businessunit_needs-create": 1, + "businessunit_resolved": 0, + "businessunit_unresolved": 0, + "export_rows": 2, + "in_scope": 1, + "location_blank": 0, + "location_needs-create": 0, + "location_resolved": 1, + "location_unresolved": 0, + "non_workstation_rows": 1, + "skipped_no_existing_machine": 0 + }, + "uncreatable": {}, + "unresolved": {} + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/settings/asset-import/winc/preview", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Read-only WINC analysis: report what a commit would do. Writes nothing.", + "example": "curl -X POST http://localhost:5001/api/settings/asset-import/winc/preview -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "blocking": true, + "committed": false, + "kind": "winc-machine-adoption", + "needscreate": { + "businessunit": { + "Large Parts": 1 + }, + "location": { + "T6": 1 + } + }, + "planhash": "", + "rowcount": 1, + "summary": { + "ambiguous_match": 0, + "businessunit_blank": 0, + "businessunit_needs-create": 1, + "businessunit_resolved": 0, + "businessunit_unresolved": 0, + "export_rows": 1, + "in_scope": 1, + "location_blank": 0, + "location_needs-create": 1, + "location_resolved": 0, + "location_unresolved": 0, + "non_workstation_rows": 0, + "skipped_no_existing_machine": 0 + }, + "uncreatable": { + "location": { + "T6": 1 + } + }, + "unresolved": {} + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/settings/asset-import/winc/undo", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Reverse an applied WINC import batch by id. Conservative and reversible.", + "example": "curl -X POST http://localhost:5001/api/settings/asset-import/winc/undo -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "batchid": "" + }, + "responseexample": { + "data": { + "batchid": "", + "conflicts": [ + { + "column": null, + "operation": "insert", + "reason": "still referenced by dashboarddefaults.businessunitid", + "table": "businessunits", + "targetid": 1 + } + ], + "reverted": 3 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/settings/branding-logo", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Upload a branding logo image and point the matching setting at it.", + "example": "curl -X POST http://localhost:5001/api/settings/branding-logo -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "key": "site_favicon", + "value": "/api/settings/branding/logo-favicon.ico" + }, + "message": "Logo uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/settings/branding/", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "path: filename (path)", + "purpose": "Serve an uploaded branding logo (public - kiosks/print pages read it).", + "example": "curl http://localhost:5001/api/settings/branding/example.png" + }, + { + "method": "POST", + "path": "/api/settings/map-blueprint", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Upload a floor-map blueprint image and point the setting at it.", + "example": "curl -X POST http://localhost:5001/api/settings/map-blueprint -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/settings/map-blueprint/", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "path: filename (path)", + "purpose": "Serve an uploaded blueprint image (public - kiosks read it).", + "example": "curl http://localhost:5001/api/settings/map-blueprint/example.png" + }, + { + "method": "POST", + "path": "/api/settings/seed", + "auth": "permission:settings.edit", + "params": "body: JSON (fields not yet documented)", + "purpose": "Seed default settings if they don't exist.", + "example": "curl -X POST http://localhost:5001/api/settings/seed -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": {}, + "responseexample": { + "data": { + "created": 112 + }, + "message": "112 default settings created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/settings/test-email", + "auth": "permission:settings.edit", + "params": "body: JSON (fields not yet documented)", + "purpose": "Send a test email to verify SMTP configuration.", + "example": "curl -X POST http://localhost:5001/api/settings/test-email -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "to": "" + }, + "responseexample": { + "data": { + "error": "[Errno -2] Name or service not known", + "sent": false + }, + "message": "Test email failed: [Errno -2] Name or service not known", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + } + ] + }, + { + "surface": "core-setup", + "endpoints": [ + { + "method": "POST", + "path": "/api/setup/complete", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Flag the first-run setup as finished.", + "example": "curl -X POST http://localhost:5001/api/setup/complete -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "POST", + "path": "/api/setup/create-admin", + "auth": "none (first run only: refused once an admin exists)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create the first admin. Only works while there are zero users, setup has not been marked complete, and the caller proves operator control (setup token or a loopback request).", + "example": "curl -X POST http://localhost:5001/api/setup/create-admin -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/setup/needs-admin", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "True when no users exist yet - the app's very first run. Public so the login screen can offer to create the first admin.", + "example": "curl http://localhost:5001/api/setup/needs-admin", + "responseexample": { + "data": { + "needsadmin": false + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/setup/seed-reference", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Seed core reference data + permissions + default settings. Idempotent - reuses the same routines as the `flask seed ...` CLI commands.", + "example": "curl -X POST http://localhost:5001/api/setup/seed-reference -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "POST", + "path": "/api/setup/seed-starter", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Add common vendors that are not already present. Idempotent.", + "example": "curl -X POST http://localhost:5001/api/setup/seed-starter -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + } + ] + }, + { + "surface": "core-shopdbbackups", + "endpoints": [ + { + "method": "GET", + "path": "/api/shopdbbackups", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "List every retained backup set, newest first, with a compatibility flag.", + "example": "curl http://localhost:5001/api/shopdbbackups -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "count": 0, + "lastgoodat": null, + "requestid": "00000000", + "retention": { + "keepdaily": 5, + "keepmonthly": 6, + "keepweekly": 4 + }, + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/shopdbbackups", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Kick off an on-demand backup run.", + "example": "curl -X POST http://localhost:5001/api/shopdbbackups -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "GET", + "path": "/api/shopdbbackups/", + "auth": "jwt + role:admin", + "params": "path: snapshotid (string)", + "purpose": "Return one set's full manifest plus a resolved compatibility verdict.", + "example": "curl http://localhost:5001/api/shopdbbackups/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/shopdbbackups//restore", + "auth": "jwt + role:admin", + "params": "path: snapshotid (string); body: JSON (fields not yet documented)", + "purpose": "Queue a restore of a set, gated on schema compatibility.", + "example": "curl -X POST http://localhost:5001/api/shopdbbackups/x/restore -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "POST", + "path": "/api/shopdbbackups/finalize-restore", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Run the post-restore schema upgrade in the app context.", + "example": "curl -X POST http://localhost:5001/api/shopdbbackups/finalize-restore -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "queued": true, + "snapshotid": "wj-2026-09-06T120000Z" + }, + "message": "Schema upgrade queued.", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/shopdbbackups/history", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "Return the recorded history of backup and restore runs, newest first.", + "example": "curl http://localhost:5001/api/shopdbbackups/history -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "backups": [], + "restores": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/shopdbbackups/settings", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "Return destination + retention config for the settings pane.", + "example": "curl http://localhost:5001/api/shopdbbackups/settings -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "backupsroot": "/backups", + "destinationkind": "local", + "destinationkinds": [ + "local", + "smb", + "aws" + ], + "fields": {}, + "isarmed": true, + "retention": { + "keepdaily": 5, + "keepmonthly": 6, + "keepweekly": 4 } - ] - }, - { - "surface": "core-operatingsystems", - "endpoints": [ - { - "method": "GET", - "path": "/api/operatingsystems", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all operating systems.", - "example": "curl http://localhost:5001/api/operatingsystems -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/operatingsystems", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new operating system.", - "example": "curl -X POST http://localhost:5001/api/operatingsystems -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/operatingsystems/", - "auth": "jwt + role:admin", - "params": "path: os_id (int)", - "purpose": "Delete (deactivate) an operating system.", - "example": "curl -X DELETE http://localhost:5001/api/operatingsystems/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/operatingsystems/", - "auth": "permission:assets.view", - "params": "path: os_id (int)", - "purpose": "Get a single operating system.", - "example": "curl http://localhost:5001/api/operatingsystems/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/operatingsystems/", - "auth": "jwt + role:admin", - "params": "path: os_id (int); body: JSON (fields not yet documented)", - "purpose": "Update an operating system.", - "example": "curl -X PUT http://localhost:5001/api/operatingsystems/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/shopdbbackups/settings", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Persist the backup destination kind and its credential/config fields.", + "example": "curl -X PUT http://localhost:5001/api/shopdbbackups/settings -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": {}, + "responseexample": { + "data": { + "backupsroot": "/backups", + "destinationkind": "local", + "destinationkinds": [ + "local", + "smb", + "aws" + ], + "fields": {}, + "isarmed": true, + "retention": { + "keepdaily": 5, + "keepmonthly": 6, + "keepweekly": 4 } - ] - }, - { - "surface": "core-plugins", - "endpoints": [ + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/shopdbbackups/status", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "Return the live status of the most recent backup and restore runs.", + "example": "curl http://localhost:5001/api/shopdbbackups/status -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "backup": null, + "restore": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "core-supportteams", + "endpoints": [ + { + "method": "GET", + "path": "/api/supportteams", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List support teams (with contacts). ?active and ?teamname filters.", + "example": "curl http://localhost:5001/api/supportteams -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "teamname", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/plugins", - "auth": "permission:settings.view", - "params": "not documented", - "purpose": "List all discovered plugins (enabled or not) with their metadata and the framework contract version.", - "example": "curl http://localhost:5001/api/plugins -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/plugins/", - "auth": "jwt + role:admin", - "params": "path: name (string); body: JSON (fields not yet documented)", - "purpose": "Enable or disable a plugin. Takes effect on the next app restart for route/navigation changes.", - "example": "curl -X PUT http://localhost:5001/api/plugins/x -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/plugins/enabled", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "Return just the names of enabled plugins as a flat array.", - "example": "curl http://localhost:5001/api/plugins/enabled -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/plugins/settings-routes", - "auth": "permission:settings.view", - "params": "not documented", - "purpose": "Return settings routes contributed by all enabled plugins.", - "example": "curl http://localhost:5001/api/plugins/settings-routes -H \"Authorization: Bearer $TOK\"" + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "supportteamid": 1, + "teamname": "Retired", + "teamurl": null, + "webhookurl": null } - ] - }, - { - "surface": "core-pluginui", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/supportteams", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new support team.", + "example": "curl -X POST http://localhost:5001/api/supportteams -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "createddate": "2026-01-01 00:00:00", + "modifieddate": "2026-01-01T00:00:00", + "teamname": "Legacy" + }, + "responseexample": { + "data": { + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "supportteamid": 1, + "teamname": "Controls", + "teamurl": "https://servicenow.example/group/controls", + "webhookurl": null + }, + "message": "Support team created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/supportteams/", + "auth": "jwt + role:admin", + "params": "path: team_id (int)", + "purpose": "Delete a support team; 409 while any application references it.", + "example": "curl -X DELETE http://localhost:5001/api/supportteams/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Support team deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/supportteams/", + "auth": "permission:assets.view", + "params": "path: team_id (int)", + "purpose": "Get a single support team with its contacts.", + "example": "curl http://localhost:5001/api/supportteams/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "contacts": [ + { + "contactid": 2, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "First", + "sortorder": 1, + "sso": "111", + "supportteamid": 1 + }, + { + "contactid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Second", + "sortorder": 2, + "sso": "222", + "supportteamid": 1 + } + ], + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "supportteamid": 1, + "teamname": "Controls", + "teamurl": null, + "webhookurl": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/supportteams/", + "auth": "jwt + role:admin", + "params": "path: team_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a support team.", + "example": "curl -X PUT http://localhost:5001/api/supportteams/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "teamname": "Controls Renamed", + "teamurl": "https://x.example" + }, + "responseexample": { + "data": { + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "supportteamid": 1, + "teamname": "Controls Renamed", + "teamurl": "https://x.example", + "webhookurl": null + }, + "message": "Support team updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/supportteams//contacts", + "auth": "jwt + role:admin", + "params": "path: team_id (int); body: JSON (fields not yet documented)", + "purpose": "Add a contact to a support team.", + "example": "curl -X POST http://localhost:5001/api/supportteams/1/contacts -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "createddate": "2026-01-01 00:00:00", + "modifieddate": "2026-01-01T00:00:00", + "name": "LegacyOwner" + }, + "responseexample": { + "data": { + "contactid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Second", + "sortorder": 2, + "sso": "222", + "supportteamid": 1 + }, + "message": "Contact created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/supportteams//contacts/", + "auth": "jwt + role:admin", + "params": "path: team_id (int), contact_id (int)", + "purpose": "Delete a support-team contact.", + "example": "curl -X DELETE http://localhost:5001/api/supportteams/1/contacts/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Contact deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/supportteams//contacts/", + "auth": "jwt + role:admin", + "params": "path: team_id (int), contact_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a support-team contact.", + "example": "curl -X PUT http://localhost:5001/api/supportteams/1/contacts/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "name": "First Updated" + }, + "responseexample": { + "data": { + "contactid": 2, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "First Updated", + "sortorder": 1, + "sso": "111", + "supportteamid": 1 + }, + "message": "Contact updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + } + ] + }, + { + "surface": "core-users", + "endpoints": [ + { + "method": "GET", + "path": "/api/users", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "List all users.", + "example": "curl http://localhost:5001/api/users -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/pluginui/asset-panels", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Return the asset-detail panels matching one asset's type (get_asset_panels).", - "example": "curl http://localhost:5001/api/pluginui/asset-panels -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/pluginui/asset-presentation", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Merge enabled plugins' asset-type presentation entries (hook).", - "example": "curl http://localhost:5001/api/pluginui/asset-presentation -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/pluginui/asset-type-descriptors", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Merge enabled plugins' asset-type subtype descriptors.", - "example": "curl http://localhost:5001/api/pluginui/asset-type-descriptors -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/pluginui/core-type-descriptors", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Return type descriptors for core-owned non-asset types.", - "example": "curl http://localhost:5001/api/pluginui/core-type-descriptors -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/pluginui/map-overlays", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Merge enabled plugins' map overlay declarations (get_map_overlays hook).", - "example": "curl http://localhost:5001/api/pluginui/map-overlays -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/pluginui/settings-cards", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Merge enabled plugins' settings-catalog cards (get_settings_cards hook).", - "example": "curl http://localhost:5001/api/pluginui/settings-cards -H \"Authorization: Bearer $TOK\"" + "createddate": "2026-01-01T00:00:00.000000Z", + "directpermissions": [], + "email": "", + "failedlogins": 0, + "firstname": "", + "isactive": true, + "islocked": false, + "lastlogindate": "2026-01-01T00:00:00Z", + "lastname": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "mustchangepassword": "", + "permissions": [ + "apitokens.create", + "applications.create", + "applications.delete", + "" + ], + "roles": [ + { + "color": null, + "roleid": 1, + "rolename": "admin" + } + ], + "userid": 1, + "username": "" } - ] - }, - { - "surface": "core-reports", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/users", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new user.", + "example": "curl -X POST http://localhost:5001/api/users -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "directpermissions": [ + "endpoints.runscript" + ], + "email": "", + "password": "", + "roles": [], + "sendwelcome": false, + "username": "" + }, + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "directpermissions": [ + "endpoints.restart" + ], + "email": "", + "failedlogins": 0, + "firstname": "", + "isactive": true, + "islocked": false, + "lastlogindate": null, + "lastname": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "mustchangepassword": "", + "permissions": [ + "applications.view", + "assets.view", + "backups.download", + "" + ], + "roles": [ + { + "color": "#0DCAF0", + "roleid": 3, + "rolename": "technician" + } + ], + "userid": 2, + "username": "", + "warning": "User created but the welcome email could not be sent." + }, + "message": "User created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/users/", + "auth": "jwt + role:admin", + "params": "path: userid (int)", + "purpose": "Delete a user.", + "example": "curl -X DELETE http://localhost:5001/api/users/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "User deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/users/", + "auth": "jwt", + "params": "path: userid (int)", + "purpose": "Get a single user.", + "example": "curl http://localhost:5001/api/users/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "directpermissions": [], + "email": "", + "failedlogins": 0, + "firstname": "", + "isactive": true, + "islocked": false, + "lastlogindate": "2026-01-01T00:00:00Z", + "lastname": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "mustchangepassword": "", + "permissions": [], + "roles": [], + "userid": 1, + "username": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/users/", + "auth": "jwt", + "params": "path: userid (int); body: JSON (fields not yet documented)", + "purpose": "Update a user.", + "example": "curl -X PUT http://localhost:5001/api/users/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "password": "" + }, + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "directpermissions": [], + "email": "", + "failedlogins": 0, + "firstname": "", + "isactive": true, + "islocked": false, + "lastlogindate": null, + "lastname": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "mustchangepassword": "", + "permissions": [], + "roles": [], + "userid": 2, + "username": "" + }, + "message": "User updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/users/permissions", + "auth": "jwt", + "params": "not documented", + "purpose": "List assignable permissions grouped by category.", + "example": "curl http://localhost:5001/api/users/permissions -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/users/roles", + "auth": "jwt", + "params": "not documented", + "purpose": "List all roles with their permissions.", + "example": "curl http://localhost:5001/api/users/roles -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/reports", - "auth": "permission:reports.view", - "params": "not documented", - "purpose": "List all available reports.", - "example": "curl http://localhost:5001/api/reports -H \"Authorization: Bearer $TOK\"" + "color": null, + "description": "Administrator", + "grantable": null, + "isadmin": true, + "isguest": false, + "permissions": [], + "roleid": 1, + "rolename": "admin", + "usercount": 1 }, { - "method": "GET", - "path": "/api/reports/asset-inventory", - "auth": "permission:reports.view", - "params": "not documented", - "purpose": "Report: Complete asset inventory summary.", - "example": "curl http://localhost:5001/api/reports/asset-inventory -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/reports/assets-by-status", - "auth": "permission:reports.view", - "params": "not documented", - "purpose": "Report: Asset count grouped by status.", - "example": "curl http://localhost:5001/api/reports/assets-by-status -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/reports/email", - "auth": "permission:reports.export", - "params": "body: JSON (fields not yet documented)", - "purpose": "Email a report's data as an HTML table (on-demand delivery).", - "example": "curl -X POST http://localhost:5001/api/reports/email -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/reports/kb-popularity", - "auth": "permission:reports.view", - "params": "not documented", - "purpose": "Report: Most clicked knowledge base articles.", - "example": "curl http://localhost:5001/api/reports/kb-popularity -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/reports/machines-by-type", - "auth": "permission:reports.view", - "params": "not documented", - "purpose": "Report: Machine count grouped by machine type.", - "example": "curl http://localhost:5001/api/reports/machines-by-type -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/reports/pc-relationships", - "auth": "permission:reports.view", - "params": "not documented", - "purpose": "Report: PCs with relationships to shop floor machines.", - "example": "curl http://localhost:5001/api/reports/pc-relationships -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/reports/software-compliance", - "auth": "permission:reports.view", - "params": "not documented", - "purpose": "Report: Required applications vs installed (per PC).", - "example": "curl http://localhost:5001/api/reports/software-compliance -H \"Authorization: Bearer $TOK\"" + "color": "#6C757D", + "description": "Anyone who is not signed in. Holds nothing by default; grant it a permission to open that up to people with no account.", + "grantable": [ + "applications.view", + "assets.view", + "computers.view", + "" + ], + "isadmin": false, + "isguest": true, + "permissions": [], + "roleid": 2, + "rolename": "guest", + "usercount": 0 } - ] - }, - { - "surface": "core-scripts", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/users/roles", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new role.", + "example": "curl -X POST http://localhost:5001/api/users/roles -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "color": "#ff8800", + "description": "colorful", + "permissions": [], + "rolename": "painters" + }, + "responseexample": { + "data": { + "color": "#ff8800", + "description": "colorful", + "permissions": [], + "roleid": 2, + "rolename": "painters" + }, + "message": "Role created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/users/roles/", + "auth": "jwt + role:admin", + "params": "path: roleid (int)", + "purpose": "Delete a role.", + "example": "curl -X DELETE http://localhost:5001/api/users/roles/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/users/roles/", + "auth": "jwt + role:admin", + "params": "path: roleid (int); body: JSON (fields not yet documented)", + "purpose": "Update a role.", + "example": "curl -X PUT http://localhost:5001/api/users/roles/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "permissions": [ + "reports.view" + ] + }, + "responseexample": { + "data": { + "color": "#6C757D", + "description": "Anyone who is not signed in. Holds nothing by default; grant it a permission to open that up to people with no account.", + "permissions": [ + "reports.view" + ], + "roleid": 2, + "rolename": "guest" + }, + "message": "Role updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + } + ] + }, + { + "surface": "core-vendors", + "endpoints": [ + { + "method": "GET", + "path": "/api/vendors", + "auth": "permission:assets.view", + "params": "not documented", + "purpose": "List all vendors.", + "example": "curl http://localhost:5001/api/vendors -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "vendor", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/scripts", - "auth": "permission:endpoints.runscript", - "params": "not documented", - "purpose": "List scripts (active by default).", - "example": "curl http://localhost:5001/api/scripts -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/scripts", - "auth": "permission:endpoints.runscript", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a script catalog entry (body uploaded separately).", - "example": "curl -X POST http://localhost:5001/api/scripts -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/scripts/", - "auth": "permission:endpoints.runscript", - "params": "path: script_id (int)", - "purpose": "UNDOCUMENTED: scripts.delete_script has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/scripts/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/scripts/", - "auth": "permission:endpoints.runscript", - "params": "path: script_id (int)", - "purpose": "UNDOCUMENTED: scripts.get_script has no docstring.", - "example": "curl http://localhost:5001/api/scripts/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/scripts/", - "auth": "permission:endpoints.runscript", - "params": "path: script_id (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: scripts.update_script has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/scripts/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/scripts//body", - "auth": "permission:endpoints.runscript", - "params": "path: script_id (int); body: JSON (fields not yet documented)", - "purpose": "Upload (or replace) the .ps1 body for a script.", - "example": "curl -X POST http://localhost:5001/api/scripts/1/body -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/scripts/body/", - "auth": "permission:endpoints.runscript", - "params": "path: filename (path)", - "purpose": "Operator-facing script body download (JWT/RBAC).", - "example": "curl http://localhost:5001/api/scripts/body/example.png -H \"Authorization: Bearer $TOK\"" + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "supportemail": "", + "supportphone": "", + "vendor": "Acme", + "vendorid": 1, + "website": null } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/vendors", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new vendor.", + "example": "curl -X POST http://localhost:5001/api/vendors -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "createddate": "2026-01-01 00:00:00", + "modifieddate": "2026-01-01T00:00:00", + "vendor": "LegacyVendor" + }, + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "supportemail": "", + "supportphone": "", + "vendor": "Unscoped Vendor", + "vendorid": 1, + "website": null + }, + "message": "Vendor created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/vendors/", + "auth": "jwt + role:admin", + "params": "path: vendor_id (int)", + "purpose": "Delete (deactivate) a vendor.", + "example": "curl -X DELETE http://localhost:5001/api/vendors/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/vendors/", + "auth": "permission:assets.view", + "params": "path: vendor_id (int)", + "purpose": "Get a single vendor.", + "example": "curl http://localhost:5001/api/vendors/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/vendors/", + "auth": "jwt + role:admin", + "params": "path: vendor_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a vendor.", + "example": "curl -X PUT http://localhost:5001/api/vendors/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "plugin-backups", + "endpoints": [ + { + "method": "GET", + "path": "/api/backups/asset/", + "auth": "permission:backups.view", + "params": "path: assetid (int)", + "purpose": "Revision history for one asset, newest first.", + "example": "curl http://localhost:5001/api/backups/asset/1 -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "kind", + "type": "string", + "required": false + } ] - }, - { - "surface": "core-search", - "endpoints": [ + }, + { + "method": "GET", + "path": "/api/backups/asset//info", + "auth": "permission:backups.view", + "params": "path: assetid (int)", + "purpose": "A kind's 'at a glance' card, built from its LATEST revision.", + "example": "curl http://localhost:5001/api/backups/asset/1/info -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "kind", + "type": "string", + "required": false + } + ] + }, + { + "method": "GET", + "path": "/api/backups/dashboard/stale", + "auth": "permission:backups.view", + "params": "not documented", + "purpose": "Chains whose backup has stopped running.", + "example": "curl http://localhost:5001/api/backups/dashboard/stale -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/backups/kinds", + "auth": "permission:backups.view", + "params": "not documented", + "purpose": "Registered backup kinds, for UI that needs to enumerate them.", + "example": "curl http://localhost:5001/api/backups/kinds -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/search", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "Global search across multiple entity types.", - "example": "curl http://localhost:5001/api/search -H \"Authorization: Bearer $TOK\"" + "assettypes": [ + "machine" + ], + "displayname": "", + "formats": [ + { + "ext": ".reg", + "hint": "Restore with the Load... button in the NTLARS settings dialog.", + "id": "ntlars", + "label": "NTLARS Load... (.reg)", + "mimetype": "application/octet-stream" + }, + { + "ext": ".reg", + "hint": "Use when importing outside NTLARS on a 64-bit machine.", + "id": "wow6432node", + "label": "Direct reg import (.reg, WOW6432Node)", + "mimetype": "application/octet-stream" + } + ], + "key": "ntlars", + "storagebackend": "shopdb" }, { - "method": "GET", - "path": "/api/search/suggest", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "A better spelling for a query that found nothing, or null.", - "example": "curl http://localhost:5001/api/search/suggest -H \"Authorization: Bearer $TOK\"" + "assettypes": [ + "machine" + ], + "displayname": "", + "formats": [], + "key": "partmarker", + "storagebackend": "share" } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/backups/revisions/", + "auth": "permission:backups.view", + "params": "path: backuprevisionid (int)", + "purpose": "One revision, including its parsed payload where there is one.", + "example": "curl http://localhost:5001/api/backups/revisions/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/backups/revisions//diff", + "auth": "permission:backups.view", + "params": "path: backuprevisionid (int)", + "purpose": "Diff two revisions of the same asset+kind.", + "example": "curl http://localhost:5001/api/backups/revisions/1/diff -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "against", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": { + "againstid": 1, + "backuprevisionid": 2, + "changecount": 1, + "changes": [ + { + "after": "OKUMA", + "aftertype": "REG_SZ", + "before": "", + "beforetype": "REG_SZ", + "change": "changed", + "keypath": "General", + "valuename": "Cnc" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/backups/revisions//download", + "auth": "permission:backups.download", + "params": "path: backuprevisionid (int)", + "purpose": "Render a revision back to its native file format.", + "example": "curl http://localhost:5001/api/backups/revisions/1/download -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "format", + "type": "string", + "required": false + } ] - }, - { - "surface": "core-settings", - "endpoints": [ + } + ] + }, + { + "surface": "plugin-computers", + "endpoints": [ + { + "method": "GET", + "path": "/api/computers", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "List all computers with filtering and pagination.", + "example": "curl http://localhost:5001/api/computers -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "assetnumber", + "type": "string", + "required": false + }, + { + "name": "businessunit_id", + "type": "integer", + "required": false + }, + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "dir", + "type": "string", + "required": false, + "default": "asc" + }, + { + "name": "location_id", + "type": "integer", + "required": false + }, + { + "name": "locationid", + "type": "integer", + "required": false + }, + { + "name": "os_id", + "type": "integer", + "required": false + }, + { + "name": "osid", + "type": "integer", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "shopfloor", + "type": "string", + "required": false + }, + { + "name": "sort", + "type": "string", + "required": false, + "default": "hostname" + }, + { + "name": "type_id", + "type": "integer", + "required": false + }, + { + "name": "typeid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/settings", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "List all settings, optionally filtered by category.", - "example": "curl http://localhost:5001/api/settings -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/settings", - "auth": "permission:settings.edit", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new setting (admin only).", - "example": "curl -X POST http://localhost:5001/api/settings -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/settings/", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "path: key (string)", - "purpose": "Get a single setting by key.", - "example": "curl http://localhost:5001/api/settings/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/settings/", - "auth": "permission:settings.edit", - "params": "path: key (string); body: JSON (fields not yet documented)", - "purpose": "Update a setting value.", - "example": "curl -X PUT http://localhost:5001/api/settings/x -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/settings/asset-import/import", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Validate uploaded CSVs and, when commit=true, load them.", - "example": "curl -X POST http://localhost:5001/api/settings/asset-import/import -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/settings/asset-import/script", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "Download Collect-ShopDB.ps1 with this site's CSV path embedded.", - "example": "curl http://localhost:5001/api/settings/asset-import/script -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/settings/asset-import/templates", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "List the importable CSV tables in the order they must be uploaded.", - "example": "curl http://localhost:5001/api/settings/asset-import/templates -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/settings/asset-import/templates/", - "auth": "jwt + role:admin", - "params": "path: tablename (string)", - "purpose": "Download a generated CSV template for a single importable table.", - "example": "curl http://localhost:5001/api/settings/asset-import/templates/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/settings/asset-import/winc/batches", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "List applied/undone WINC import batches, newest first (for the undo UI).", - "example": "curl http://localhost:5001/api/settings/asset-import/winc/batches -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/settings/asset-import/winc/commit", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Apply a WINC plan reversibly. Requires acknowledgment for needs-create.", - "example": "curl -X POST http://localhost:5001/api/settings/asset-import/winc/commit -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/settings/asset-import/winc/preview", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Read-only WINC analysis: report what a commit would do. Writes nothing.", - "example": "curl -X POST http://localhost:5001/api/settings/asset-import/winc/preview -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/settings/asset-import/winc/undo", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Reverse an applied WINC import batch by id. Conservative and reversible.", - "example": "curl -X POST http://localhost:5001/api/settings/asset-import/winc/undo -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/settings/branding-logo", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Upload a branding logo image and point the matching setting at it.", - "example": "curl -X POST http://localhost:5001/api/settings/branding-logo -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/settings/branding/", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "path: filename (path)", - "purpose": "Serve an uploaded branding logo (public - kiosks/print pages read it).", - "example": "curl http://localhost:5001/api/settings/branding/example.png" - }, - { - "method": "POST", - "path": "/api/settings/map-blueprint", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Upload a floor-map blueprint image and point the setting at it.", - "example": "curl -X POST http://localhost:5001/api/settings/map-blueprint -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/settings/map-blueprint/", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "path: filename (path)", - "purpose": "Serve an uploaded blueprint image (public - kiosks read it).", - "example": "curl http://localhost:5001/api/settings/map-blueprint/example.png" - }, - { - "method": "POST", - "path": "/api/settings/seed", - "auth": "permission:settings.edit", - "params": "body: JSON (fields not yet documented)", - "purpose": "Seed default settings if they don't exist.", - "example": "curl -X POST http://localhost:5001/api/settings/seed -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/settings/test-email", - "auth": "permission:settings.edit", - "params": "body: JSON (fields not yet documented)", - "purpose": "Send a test email to verify SMTP configuration.", - "example": "curl -X POST http://localhost:5001/api/settings/test-email -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "accessmethods": [], + "assetid": 1, + "assetnumber": "PC-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "computer", + "businessunitid": null, + "computer": { + "accessprotocolnames": [], + "assetid": 1, + "azuredevicecategory": null, + "azuredeviceid": null, + "azureobjectid": null, + "computerid": 1, + "computertypeid": 1, + "computertypename": "Standard", + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "isactive": true, + "lastboottime": null, + "lastreporteddate": null, + "loggedinuser": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "osid": null, + "vendorid": null + }, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 } - ] - }, - { - "surface": "core-setup", - "endpoints": [ + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/computers", + "auth": "permission:computers.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create new computer (creates both Asset and Computer records).", + "example": "curl -X POST http://localhost:5001/api/computers -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "assetnumber": "PC-IMPORT-1", + "createddate": "2026-01-01 00:00:00", + "hostname": "", + "modifieddate": "2026-01-01T00:00:00" + }, + "responseexample": { + "data": { + "accessmethods": [], + "assetid": 1, + "assetnumber": "AUDIT-PC-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "computer", + "businessunitid": null, + "computer": { + "accessprotocolnames": [], + "assetid": 1, + "azuredevicecategory": null, + "azuredeviceid": null, + "azureobjectid": null, + "computerid": 1, + "computertypeid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "isactive": true, + "lastboottime": null, + "lastreporteddate": null, + "loggedinuser": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "osid": null, + "vendorid": null + }, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "message": "Computer created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/computers/", + "auth": "permission:computers.delete", + "params": "path: computer_id (int)", + "purpose": "Delete (soft delete) computer.", + "example": "curl -X DELETE http://localhost:5001/api/computers/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/", + "auth": "permission:computers.view", + "params": "path: computer_id (int)", + "purpose": "Get a single computer with full details.", + "example": "curl http://localhost:5001/api/computers/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "accessmethods": [], + "assetid": 1, + "assetnumber": "PC-2001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "computer", + "businessunitid": null, + "communications": [], + "computer": { + "accessprotocolnames": [], + "assetid": 1, + "azuredevicecategory": null, + "azuredeviceid": null, + "azureobjectid": null, + "computerid": 1, + "computertypeid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "imageurl": "/api/models/images/model-1.png", + "isactive": true, + "lastboottime": null, + "lastreporteddate": null, + "loggedinuser": null, + "modelname": "IMG-MODEL-1", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "osid": null, + "vendorid": null + }, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/computers/", + "auth": "permission:computers.edit", + "params": "path: computer_id (int); body: JSON (fields not yet documented)", + "purpose": "Update computer (both Asset and Computer records).", + "example": "curl -X PUT http://localhost:5001/api/computers/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "gaugelabreference": "GL-2", + "maintenancereference": "MNT-2" + }, + "responseexample": { + "data": { + "accessmethods": [ + { + "id": 1, + "link": "rdp://auditpc1", + "name": "RDP", + "port": null, + "portoverride": null, + "protocolid": 1, + "scheme": "rdp" + } + ], + "assetid": 1, + "assetnumber": "AUDIT-PC-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "computer", + "businessunitid": null, + "computer": { + "accessprotocolnames": [ + "RDP" + ], + "assetid": 1, + "azuredevicecategory": null, + "azuredeviceid": null, + "azureobjectid": null, + "computerid": 1, + "computertypeid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "isactive": true, + "lastboottime": null, + "lastreporteddate": null, + "loggedinuser": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "osid": null, + "vendorid": null + }, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "message": "Computer updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/computers//apps", + "auth": "permission:computers.view", + "params": "path: computer_id (int)", + "purpose": "Get all installed applications for a computer.", + "example": "curl http://localhost:5001/api/computers/1/apps -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/computers//apps", + "auth": "permission:computers.create", + "params": "path: computer_id (int); body: JSON (fields not yet documented)", + "purpose": "Add an installed application to a computer.", + "example": "curl -X POST http://localhost:5001/api/computers/1/apps -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/computers//apps/", + "auth": "permission:computers.delete", + "params": "path: computer_id (int), app_id (int)", + "purpose": "Remove an installed application from a computer.", + "example": "curl -X DELETE http://localhost:5001/api/computers/1/apps/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/computers//report", + "auth": "permission:computers.create", + "params": "path: computer_id (int); body: JSON (fields not yet documented)", + "purpose": "Report computer status (for agent-based reporting).", + "example": "curl -X POST http://localhost:5001/api/computers/1/report -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/computers/asset//policypanel", + "auth": "permission:computers.view", + "params": "path: asset_id (int)", + "purpose": "Keyvalue panel: which policy governs this endpoint, and what it allows.", + "example": "curl http://localhost:5001/api/computers/asset/1/policypanel -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/by-asset/", + "auth": "permission:computers.view", + "params": "path: asset_id (int)", + "purpose": "Get computer data by asset ID.", + "example": "curl http://localhost:5001/api/computers/by-asset/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/by-hostname/", + "auth": "permission:computers.view", + "params": "path: hostname (string)", + "purpose": "Get computer by hostname.", + "example": "curl http://localhost:5001/api/computers/by-hostname/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/client-script", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "The collector reporter, stamped with THIS site's values.", + "example": "curl http://localhost:5001/api/computers/client-script -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/dashboard/quiet", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "PCs that WERE reporting, have stopped, and are still meant to be in use.", + "example": "curl http://localhost:5001/api/computers/dashboard/quiet -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "POST", - "path": "/api/setup/complete", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Flag the first-run setup as finished.", - "example": "curl -X POST http://localhost:5001/api/setup/complete -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "computerid": 2, + "hostname": "", + "lastreported": "2026-01-01T00:00:00.000000Z", + "quietdays": 9 }, { - "method": "POST", - "path": "/api/setup/create-admin", - "auth": "none (first run only: refused once an admin exists)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create the first admin. Only works while there are zero users, setup has not been marked complete, and the caller proves operator control (setup token or a loopback request).", - "example": "curl -X POST http://localhost:5001/api/setup/create-admin -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/setup/needs-admin", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "True when no users exist yet - the app's very first run. Public so the login screen can offer to create the first admin.", - "example": "curl http://localhost:5001/api/setup/needs-admin" - }, - { - "method": "POST", - "path": "/api/setup/seed-reference", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Seed core reference data + permissions + default settings. Idempotent - reuses the same routines as the `flask seed ...` CLI commands.", - "example": "curl -X POST http://localhost:5001/api/setup/seed-reference -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/setup/seed-starter", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Add common vendors that are not already present. Idempotent.", - "example": "curl -X POST http://localhost:5001/api/setup/seed-starter -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "computerid": 1, + "hostname": "", + "lastreported": "2026-01-01T00:00:00.000000Z", + "quietdays": 2 } - ] - }, - { - "surface": "core-shopdbbackups", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/computers/dashboard/sharedmachines", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "Machine numbers claimed by more than one PC, with nothing filed under them.", + "example": "curl http://localhost:5001/api/computers/dashboard/sharedmachines -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/shopdbbackups", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "List every retained backup set, newest first, with a compatibility flag.", - "example": "curl http://localhost:5001/api/shopdbbackups -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/shopdbbackups", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Kick off an on-demand backup run.", - "example": "curl -X POST http://localhost:5001/api/shopdbbackups -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/shopdbbackups/", - "auth": "jwt + role:admin", - "params": "path: snapshotid (string)", - "purpose": "Return one set's full manifest plus a resolved compatibility verdict.", - "example": "curl http://localhost:5001/api/shopdbbackups/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/shopdbbackups//restore", - "auth": "jwt + role:admin", - "params": "path: snapshotid (string); body: JSON (fields not yet documented)", - "purpose": "Queue a restore of a set, gated on schema compatibility.", - "example": "curl -X POST http://localhost:5001/api/shopdbbackups/x/restore -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/shopdbbackups/finalize-restore", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Run the post-restore schema upgrade in the app context.", - "example": "curl -X POST http://localhost:5001/api/shopdbbackups/finalize-restore -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/shopdbbackups/history", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "Return the recorded history of backup and restore runs, newest first.", - "example": "curl http://localhost:5001/api/shopdbbackups/history -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/shopdbbackups/settings", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "Return destination + retention config for the settings pane.", - "example": "curl http://localhost:5001/api/shopdbbackups/settings -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/shopdbbackups/settings", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Persist the backup destination kind and its credential/config fields.", - "example": "curl -X PUT http://localhost:5001/api/shopdbbackups/settings -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/shopdbbackups/status", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "Return the live status of the most recent backup and restore runs.", - "example": "curl http://localhost:5001/api/shopdbbackups/status -H \"Authorization: Bearer $TOK\"" + "assetid": 1, + "machinenumber": "2026", + "pccount": 2, + "pcs": "PCONE, PCTWO" } - ] - }, - { - "surface": "core-supportteams", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/computers/dashboard/summary", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "Get computer dashboard summary data.", + "example": "curl http://localhost:5001/api/computers/dashboard/summary -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "byos": [], + "bytype": [], + "nonshopfloor": 0, + "shopfloor": 0, + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/computers/display-kiosks", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "Reporting display kiosks, for the Dashboard Defaults picker.", + "example": "curl http://localhost:5001/api/computers/display-kiosks -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/supportteams", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List support teams (with contacts). ?active and ?teamname filters.", - "example": "curl http://localhost:5001/api/supportteams -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/supportteams", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new support team.", - "example": "curl -X POST http://localhost:5001/api/supportteams -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/supportteams/", - "auth": "jwt + role:admin", - "params": "path: team_id (int)", - "purpose": "Delete a support team; 409 while any application references it.", - "example": "curl -X DELETE http://localhost:5001/api/supportteams/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/supportteams/", - "auth": "permission:assets.view", - "params": "path: team_id (int)", - "purpose": "Get a single support team with its contacts.", - "example": "curl http://localhost:5001/api/supportteams/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/supportteams/", - "auth": "jwt + role:admin", - "params": "path: team_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a support team.", - "example": "curl -X PUT http://localhost:5001/api/supportteams/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/supportteams//contacts", - "auth": "jwt + role:admin", - "params": "path: team_id (int); body: JSON (fields not yet documented)", - "purpose": "Add a contact to a support team.", - "example": "curl -X POST http://localhost:5001/api/supportteams/1/contacts -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/supportteams//contacts/", - "auth": "jwt + role:admin", - "params": "path: team_id (int), contact_id (int)", - "purpose": "Delete a support-team contact.", - "example": "curl -X DELETE http://localhost:5001/api/supportteams/1/contacts/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/supportteams//contacts/", - "auth": "jwt + role:admin", - "params": "path: team_id (int), contact_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a support-team contact.", - "example": "curl -X PUT http://localhost:5001/api/supportteams/1/contacts/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "computerid": 1, + "fqdn": "", + "hostname": "", + "serialnumber": "" } - ] - }, - { - "surface": "core-users", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/computers/policies/actions", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "The allowlisted action names + labels a policy may reference.", + "example": "curl http://localhost:5001/api/computers/policies/actions -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/users", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "List all users.", - "example": "curl http://localhost:5001/api/users -H \"Authorization: Bearer $TOK\"" + "action": "service_start", + "description": "Start a Windows service by name on the endpoint.", + "kind": "command", + "label": "Start service", + "mayauthor": true, + "requiredpermission": null }, { - "method": "POST", - "path": "/api/users", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new user.", - "example": "curl -X POST http://localhost:5001/api/users -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "action": "service_stop", + "description": "Stop a running Windows service by name on the endpoint.", + "kind": "command", + "label": "Stop service", + "mayauthor": true, + "requiredpermission": null }, { - "method": "DELETE", - "path": "/api/users/", - "auth": "jwt + role:admin", - "params": "path: userid (int)", - "purpose": "Delete a user.", - "example": "curl -X DELETE http://localhost:5001/api/users/1 -H \"Authorization: Bearer $TOK\"" + "action": "service_status", + "description": "Report whether a named Windows service is running.", + "kind": "command", + "label": "Check service", + "mayauthor": true, + "requiredpermission": null }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/computers/policies/business", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "UNDOCUMENTED: computers.list_business_policies has no docstring.", + "example": "curl http://localhost:5001/api/computers/policies/business -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/computers/policies/business", + "auth": "permission:computers.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: computers.create_business_policy has no docstring.", + "example": "curl -X POST http://localhost:5001/api/computers/policies/business -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/computers/policies/business/", + "auth": "permission:computers.delete", + "params": "path: policy_id (int)", + "purpose": "UNDOCUMENTED: computers.delete_business_policy has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/computers/policies/business/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/policies/business/", + "auth": "permission:computers.view", + "params": "path: policy_id (int)", + "purpose": "UNDOCUMENTED: computers.get_business_policy has no docstring.", + "example": "curl http://localhost:5001/api/computers/policies/business/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/computers/policies/business/", + "auth": "permission:computers.edit", + "params": "path: policy_id (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: computers.update_business_policy has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/computers/policies/business/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/computers/policies/configuration", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "UNDOCUMENTED: computers.list_configuration_policies has no docstring.", + "example": "curl http://localhost:5001/api/computers/policies/configuration -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/computers/policies/configuration", + "auth": "permission:computers.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: computers.create_configuration_policy has no docstring.", + "example": "curl -X POST http://localhost:5001/api/computers/policies/configuration -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "actions": [ { - "method": "GET", - "path": "/api/users/", - "auth": "jwt", - "params": "path: userid (int)", - "purpose": "Get a single user.", - "example": "curl http://localhost:5001/api/users/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/users/", - "auth": "jwt", - "params": "path: userid (int); body: JSON (fields not yet documented)", - "purpose": "Update a user.", - "example": "curl -X PUT http://localhost:5001/api/users/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/users/permissions", - "auth": "jwt", - "params": "not documented", - "purpose": "List assignable permissions grouped by category.", - "example": "curl http://localhost:5001/api/users/permissions -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/users/roles", - "auth": "jwt", - "params": "not documented", - "purpose": "List all roles with their permissions.", - "example": "curl http://localhost:5001/api/users/roles -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/users/roles", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new role.", - "example": "curl -X POST http://localhost:5001/api/users/roles -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/users/roles/", - "auth": "jwt + role:admin", - "params": "path: roleid (int)", - "purpose": "Delete a role.", - "example": "curl -X DELETE http://localhost:5001/api/users/roles/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/users/roles/", - "auth": "jwt + role:admin", - "params": "path: roleid (int); body: JSON (fields not yet documented)", - "purpose": "Update a role.", - "example": "curl -X PUT http://localhost:5001/api/users/roles/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "action": "run_script" } + ], + "name": "Legitimate" + }, + "responseexample": { + "data": { + "actions": [ + { + "action": "run_script", + "configurationpolicyactionid": 1, + "configurationpolicyid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "desiredstate": null, + "intervalminutes": null, + "isactive": true, + "mode": "gate", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "params": null, + "sortorder": 0 + } + ], + "configurationpolicyid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Legitimate", + "scopejson": null, + "source": "local" + }, + "message": "Configuration policy created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/computers/policies/configuration/", + "auth": "permission:computers.delete", + "params": "path: policy_id (int)", + "purpose": "UNDOCUMENTED: computers.delete_configuration_policy has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/computers/policies/configuration/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/policies/configuration/", + "auth": "permission:computers.view", + "params": "path: policy_id (int)", + "purpose": "UNDOCUMENTED: computers.get_configuration_policy has no docstring.", + "example": "curl http://localhost:5001/api/computers/policies/configuration/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/computers/policies/configuration/", + "auth": "permission:computers.edit", + "params": "path: policy_id (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: computers.update_configuration_policy has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/computers/policies/configuration/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "description": "clearer wording", + "name": "New Name" + }, + "responseexample": { + "data": { + "actions": [ + { + "action": "run_script", + "configurationpolicyactionid": 1, + "configurationpolicyid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "desiredstate": null, + "intervalminutes": null, + "isactive": true, + "mode": "gate", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "params": null, + "sortorder": 0 + } + ], + "configurationpolicyid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "clearer wording", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "New Name", + "scopejson": null, + "source": "local" + }, + "message": "Configuration policy updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/computers/policies/effective/", + "auth": "permission:computers.view", + "params": "path: asset_id (int)", + "purpose": "Preview the resolved effective policy for one endpoint (debug/UI).", + "example": "curl http://localhost:5001/api/computers/policies/effective/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/protocols", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "List access protocols. ?active=false includes disabled ones.", + "example": "curl http://localhost:5001/api/computers/protocols -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + } + ], + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/computers/protocols", + "auth": "permission:computers.edit", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: computers.create_protocol has no docstring.", + "example": "curl -X POST http://localhost:5001/api/computers/protocols -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/computers/protocols/", + "auth": "permission:computers.edit", + "params": "path: protocol_id (int)", + "purpose": "UNDOCUMENTED: computers.delete_protocol has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/computers/protocols/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PATCH|PUT", + "path": "/api/computers/protocols/", + "auth": "permission:computers.edit", + "params": "path: protocol_id (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: computers.update_protocol has no docstring.", + "example": "curl -X PATCH http://localhost:5001/api/computers/protocols/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/computers/types", + "auth": "permission:computers.view", + "params": "not documented", + "purpose": "List all computer types.", + "example": "curl http://localhost:5001/api/computers/types -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/computers/types", + "auth": "permission:computers.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new computer type.", + "example": "curl -X POST http://localhost:5001/api/computers/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/computers/types/", + "auth": "permission:computers.delete", + "params": "path: type_id (int)", + "purpose": "Delete a computer type. Refused if any PC still uses it.", + "example": "curl -X DELETE http://localhost:5001/api/computers/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/computers/types/", + "auth": "permission:computers.view", + "params": "path: type_id (int)", + "purpose": "Get a single computer type.", + "example": "curl http://localhost:5001/api/computers/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/computers/types/", + "auth": "permission:computers.edit", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a computer type.", + "example": "curl -X PUT http://localhost:5001/api/computers/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "plugin-employees", + "endpoints": [ + { + "method": "DELETE", + "path": "/api/employees//photo", + "auth": "jwt + role:admin", + "params": "path: sso (int)", + "purpose": "Clear an employee photo and delete the uploaded file. External mode 409s.", + "example": "curl -X DELETE http://localhost:5001/api/employees/1/photo -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "First_Name": "Test", + "Last_Name": "Person", + "Picture": null, + "Role": null, + "SSO": 210000001, + "Team": null, + "photofilename": null, + "photourl": null + }, + "message": "Employee photo removed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/employees//photo", + "auth": "jwt + role:admin", + "params": "path: sso (int); body: JSON (fields not yet documented)", + "purpose": "Upload (or replace) the photo for a self-hosted directory employee.", + "example": "curl -X POST http://localhost:5001/api/employees/1/photo -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "First_Name": "Test", + "Last_Name": "Person", + "Picture": null, + "Role": null, + "SSO": 210000001, + "Team": null, + "photofilename": "photo-210000001.jpg", + "photourl": "/api/employees/photo/photo-210000001.jpg" + }, + "message": "Employee photo uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/employees/directory", + "auth": "permission:employees.view", + "params": "not documented", + "purpose": "Full self-hosted directory (for the management page).", + "example": "curl http://localhost:5001/api/employees/directory -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/employees/directory", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: employees.create_directory_employee has no docstring.", + "example": "curl -X POST http://localhost:5001/api/employees/directory -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/employees/directory/", + "auth": "jwt + role:admin", + "params": "path: sso (int)", + "purpose": "UNDOCUMENTED: employees.delete_directory_employee has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/employees/directory/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/employees/directory/", + "auth": "jwt + role:admin", + "params": "path: sso (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: employees.update_directory_employee has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/employees/directory/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/employees/directory/import", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Bulk upsert from CSV. Accepts headers SSO,First_Name,Last_Name,Team,Role, Picture (case-insensitive; sso/firstname/... also accepted).", + "example": "curl -X POST http://localhost:5001/api/employees/directory/import -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/employees/lookup", + "auth": "permission:employees.view", + "params": "not documented", + "purpose": "Look up multiple employees by SSO list.", + "example": "curl http://localhost:5001/api/employees/lookup -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "sso", + "type": "string", + "required": false, + "default": "" + } ] - }, - { - "surface": "core-vendors", - "endpoints": [ + }, + { + "method": "GET", + "path": "/api/employees/lookup/", + "auth": "permission:employees.view", + "params": "path: sso (string)", + "purpose": "Look up a single employee by SSO.", + "example": "curl http://localhost:5001/api/employees/lookup/x -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "First_Name": "Test", + "Last_Name": "Person", + "Picture": null, + "Role": null, + "SSO": 210000001, + "Team": null, + "photofilename": "photo-210000001.png", + "photourl": "/api/employees/photo/photo-210000001.png" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/employees/photo/", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "path: filename (path)", + "purpose": "Serve an uploaded employee photo (public - kiosk cards read it).", + "example": "curl http://localhost:5001/api/employees/photo/example.png" + }, + { + "method": "GET", + "path": "/api/employees/resolve/", + "auth": "permission:employees.view", + "params": "path: sso (string)", + "purpose": "Resolve one SSO to a name and photo, and say HOW.", + "example": "curl http://localhost:5001/api/employees/resolve/x -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "error": "No name found in the directory or in a user account", + "mode": "selfhosted", + "name": null, + "photourl": null, + "source": null, + "sso": "999999" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/employees/search", + "auth": "permission:employees.view", + "params": "not documented", + "purpose": "Search employees by name.", + "example": "curl http://localhost:5001/api/employees/search -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "limit", + "type": "integer", + "required": false, + "default": 10 + }, + { + "name": "q", + "type": "string", + "required": false, + "default": "" + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/vendors", - "auth": "permission:assets.view", - "params": "not documented", - "purpose": "List all vendors.", - "example": "curl http://localhost:5001/api/vendors -H \"Authorization: Bearer $TOK\"" + "First_Name": "Dana", + "Last_Name": "Reyes", + "Picture": null, + "Role": null, + "SSO": 990005, + "Team": null, + "photofilename": null, + "photourl": null }, { - "method": "POST", - "path": "/api/vendors", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new vendor.", - "example": "curl -X POST http://localhost:5001/api/vendors -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/vendors/", - "auth": "jwt + role:admin", - "params": "path: vendor_id (int)", - "purpose": "Delete (deactivate) a vendor.", - "example": "curl -X DELETE http://localhost:5001/api/vendors/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/vendors/", - "auth": "permission:assets.view", - "params": "path: vendor_id (int)", - "purpose": "Get a single vendor.", - "example": "curl http://localhost:5001/api/vendors/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/vendors/", - "auth": "jwt + role:admin", - "params": "path: vendor_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a vendor.", - "example": "curl -X PUT http://localhost:5001/api/vendors/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "First_Name": "Sam", + "Last_Name": "Reyes", + "Picture": null, + "Role": null, + "SSO": 990006, + "Team": null, + "photofilename": null, + "photourl": null } - ] - }, - { - "surface": "plugin-backups", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "plugin-endpoints", + "endpoints": [ + { + "method": "GET", + "path": "/api/endpoints", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "List reported endpoint states.", + "example": "curl http://localhost:5001/api/endpoints -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "businessunitid", + "type": "string", + "required": false + }, + { + "name": "computertypeid", + "type": "string", + "required": false + }, + { + "name": "credentialstate", + "type": "string", + "required": false + }, + { + "name": "locationid", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "sort", + "type": "string", + "required": false + }, + { + "name": "status", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/backups/asset/", - "auth": "permission:backups.view", - "params": "path: assetid (int)", - "purpose": "Revision history for one asset, newest first.", - "example": "curl http://localhost:5001/api/backups/asset/1 -H \"Authorization: Bearer $TOK\"" + "agentversion": "1.20.0", + "alias": "REVOKED", + "assetid": 6, + "assetnumber": "REVOKED", + "computerid": 6, + "computertype": null, + "computertypeid": null, + "cpupercent": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "credentialstate": "", + "domain": null, + "endpointstateid": 6, + "health": { + "label": "ok", + "level": "ok" + }, + "hostname": "", + "idleseconds": null, + "lastboottime": null, + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "loggedinuser": null, + "machines": [], + "memorypercent": null, + "mtconnectcheckedat": null, + "mtconnectrunning": null, + "pendingreboot": null, + "status": "reporting", + "trayversion": null, + "uptimedisplay": null, + "uptimeseconds": null }, { - "method": "GET", - "path": "/api/backups/asset//info", - "auth": "permission:backups.view", - "params": "path: assetid (int)", - "purpose": "A kind's 'at a glance' card, built from its LATEST revision.", - "example": "curl http://localhost:5001/api/backups/asset/1/info -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/backups/dashboard/stale", - "auth": "permission:backups.view", - "params": "not documented", - "purpose": "Chains whose backup has stopped running.", - "example": "curl http://localhost:5001/api/backups/dashboard/stale -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/backups/kinds", - "auth": "permission:backups.view", - "params": "not documented", - "purpose": "Registered backup kinds, for UI that needs to enumerate them.", - "example": "curl http://localhost:5001/api/backups/kinds -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/backups/revisions/", - "auth": "permission:backups.view", - "params": "path: backuprevisionid (int)", - "purpose": "One revision, including its parsed payload where there is one.", - "example": "curl http://localhost:5001/api/backups/revisions/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/backups/revisions//diff", - "auth": "permission:backups.view", - "params": "path: backuprevisionid (int)", - "purpose": "Diff two revisions of the same asset+kind.", - "example": "curl http://localhost:5001/api/backups/revisions/1/diff -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/backups/revisions//download", - "auth": "permission:backups.download", - "params": "path: backuprevisionid (int)", - "purpose": "Render a revision back to its native file format.", - "example": "curl http://localhost:5001/api/backups/revisions/1/download -H \"Authorization: Bearer $TOK\"" + "agentversion": "1.20.0", + "alias": "SHARED", + "assetid": 5, + "assetnumber": "SHARED", + "computerid": 5, + "computertype": null, + "computertypeid": null, + "cpupercent": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "credentialstate": "", + "domain": null, + "endpointstateid": 5, + "health": { + "label": "ok", + "level": "ok" + }, + "hostname": "", + "idleseconds": null, + "lastboottime": null, + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "loggedinuser": null, + "machines": [], + "memorypercent": null, + "mtconnectcheckedat": null, + "mtconnectrunning": null, + "pendingreboot": null, + "status": "reporting", + "trayversion": null, + "uptimedisplay": null, + "uptimeseconds": null } - ] - }, - { - "surface": "plugin-computers", - "endpoints": [ - { - "method": "GET", - "path": "/api/computers", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "List all computers with filtering and pagination.", - "example": "curl http://localhost:5001/api/computers -H \"Authorization: Bearer $TOK\"" + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 2, + "totalpages": 1 }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "List reported endpoint states.", + "example": "curl http://localhost:5001/api/endpoints/ -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "businessunitid", + "type": "string", + "required": false + }, + { + "name": "computertypeid", + "type": "string", + "required": false + }, + { + "name": "credentialstate", + "type": "string", + "required": false + }, + { + "name": "locationid", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "sort", + "type": "string", + "required": false + }, + { + "name": "status", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "POST", - "path": "/api/computers", - "auth": "permission:computers.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create new computer (creates both Asset and Computer records).", - "example": "curl -X POST http://localhost:5001/api/computers -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/computers/", - "auth": "permission:computers.delete", - "params": "path: computer_id (int)", - "purpose": "Delete (soft delete) computer.", - "example": "curl -X DELETE http://localhost:5001/api/computers/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/", - "auth": "permission:computers.view", - "params": "path: computer_id (int)", - "purpose": "Get a single computer with full details.", - "example": "curl http://localhost:5001/api/computers/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/computers/", - "auth": "permission:computers.edit", - "params": "path: computer_id (int); body: JSON (fields not yet documented)", - "purpose": "Update computer (both Asset and Computer records).", - "example": "curl -X PUT http://localhost:5001/api/computers/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/computers//apps", - "auth": "permission:computers.view", - "params": "path: computer_id (int)", - "purpose": "Get all installed applications for a computer.", - "example": "curl http://localhost:5001/api/computers/1/apps -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/computers//apps", - "auth": "permission:computers.create", - "params": "path: computer_id (int); body: JSON (fields not yet documented)", - "purpose": "Add an installed application to a computer.", - "example": "curl -X POST http://localhost:5001/api/computers/1/apps -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/computers//apps/", - "auth": "permission:computers.delete", - "params": "path: computer_id (int), app_id (int)", - "purpose": "Remove an installed application from a computer.", - "example": "curl -X DELETE http://localhost:5001/api/computers/1/apps/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/computers//report", - "auth": "permission:computers.create", - "params": "path: computer_id (int); body: JSON (fields not yet documented)", - "purpose": "Report computer status (for agent-based reporting).", - "example": "curl -X POST http://localhost:5001/api/computers/1/report -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/computers/asset//policypanel", - "auth": "permission:computers.view", - "params": "path: asset_id (int)", - "purpose": "Keyvalue panel: which policy governs this endpoint, and what it allows.", - "example": "curl http://localhost:5001/api/computers/asset/1/policypanel -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/by-asset/", - "auth": "permission:computers.view", - "params": "path: asset_id (int)", - "purpose": "Get computer data by asset ID.", - "example": "curl http://localhost:5001/api/computers/by-asset/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/by-hostname/", - "auth": "permission:computers.view", - "params": "path: hostname (string)", - "purpose": "Get computer by hostname.", - "example": "curl http://localhost:5001/api/computers/by-hostname/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/client-script", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "The collector reporter, stamped with THIS site's values.", - "example": "curl http://localhost:5001/api/computers/client-script -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/dashboard/quiet", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "PCs that WERE reporting, have stopped, and are still meant to be in use.", - "example": "curl http://localhost:5001/api/computers/dashboard/quiet -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/dashboard/sharedmachines", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "Machine numbers claimed by more than one PC, with nothing filed under them.", - "example": "curl http://localhost:5001/api/computers/dashboard/sharedmachines -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/dashboard/summary", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "Get computer dashboard summary data.", - "example": "curl http://localhost:5001/api/computers/dashboard/summary -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/display-kiosks", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "Reporting display kiosks, for the Dashboard Defaults picker.", - "example": "curl http://localhost:5001/api/computers/display-kiosks -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/policies/actions", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "The allowlisted action names + labels a policy may reference.", - "example": "curl http://localhost:5001/api/computers/policies/actions -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/policies/business", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "UNDOCUMENTED: computers.list_business_policies has no docstring.", - "example": "curl http://localhost:5001/api/computers/policies/business -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/computers/policies/business", - "auth": "permission:computers.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: computers.create_business_policy has no docstring.", - "example": "curl -X POST http://localhost:5001/api/computers/policies/business -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/computers/policies/business/", - "auth": "permission:computers.delete", - "params": "path: policy_id (int)", - "purpose": "UNDOCUMENTED: computers.delete_business_policy has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/computers/policies/business/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/policies/business/", - "auth": "permission:computers.view", - "params": "path: policy_id (int)", - "purpose": "UNDOCUMENTED: computers.get_business_policy has no docstring.", - "example": "curl http://localhost:5001/api/computers/policies/business/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/computers/policies/business/", - "auth": "permission:computers.edit", - "params": "path: policy_id (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: computers.update_business_policy has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/computers/policies/business/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/computers/policies/configuration", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "UNDOCUMENTED: computers.list_configuration_policies has no docstring.", - "example": "curl http://localhost:5001/api/computers/policies/configuration -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/computers/policies/configuration", - "auth": "permission:computers.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: computers.create_configuration_policy has no docstring.", - "example": "curl -X POST http://localhost:5001/api/computers/policies/configuration -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/computers/policies/configuration/", - "auth": "permission:computers.delete", - "params": "path: policy_id (int)", - "purpose": "UNDOCUMENTED: computers.delete_configuration_policy has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/computers/policies/configuration/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/policies/configuration/", - "auth": "permission:computers.view", - "params": "path: policy_id (int)", - "purpose": "UNDOCUMENTED: computers.get_configuration_policy has no docstring.", - "example": "curl http://localhost:5001/api/computers/policies/configuration/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/computers/policies/configuration/", - "auth": "permission:computers.edit", - "params": "path: policy_id (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: computers.update_configuration_policy has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/computers/policies/configuration/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/computers/policies/effective/", - "auth": "permission:computers.view", - "params": "path: asset_id (int)", - "purpose": "Preview the resolved effective policy for one endpoint (debug/UI).", - "example": "curl http://localhost:5001/api/computers/policies/effective/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/protocols", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "List access protocols. ?active=false includes disabled ones.", - "example": "curl http://localhost:5001/api/computers/protocols -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/computers/protocols", - "auth": "permission:computers.edit", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: computers.create_protocol has no docstring.", - "example": "curl -X POST http://localhost:5001/api/computers/protocols -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/computers/protocols/", - "auth": "permission:computers.edit", - "params": "path: protocol_id (int)", - "purpose": "UNDOCUMENTED: computers.delete_protocol has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/computers/protocols/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PATCH|PUT", - "path": "/api/computers/protocols/", - "auth": "permission:computers.edit", - "params": "path: protocol_id (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: computers.update_protocol has no docstring.", - "example": "curl -X PATCH http://localhost:5001/api/computers/protocols/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/computers/types", - "auth": "permission:computers.view", - "params": "not documented", - "purpose": "List all computer types.", - "example": "curl http://localhost:5001/api/computers/types -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/computers/types", - "auth": "permission:computers.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new computer type.", - "example": "curl -X POST http://localhost:5001/api/computers/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/computers/types/", - "auth": "permission:computers.delete", - "params": "path: type_id (int)", - "purpose": "Delete a computer type. Refused if any PC still uses it.", - "example": "curl -X DELETE http://localhost:5001/api/computers/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/computers/types/", - "auth": "permission:computers.view", - "params": "path: type_id (int)", - "purpose": "Get a single computer type.", - "example": "curl http://localhost:5001/api/computers/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/computers/types/", - "auth": "permission:computers.edit", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a computer type.", - "example": "curl -X PUT http://localhost:5001/api/computers/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "agentversion": null, + "alias": "Bay 3 Controller", + "assetid": 1, + "assetnumber": "fleetbox", + "computerid": 1, + "computertype": null, + "computertypeid": null, + "cpupercent": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "credentialstate": "", + "domain": null, + "endpointstateid": 1, + "health": { + "label": "no agent", + "level": "unknown" + }, + "hostname": "", + "idleseconds": null, + "lastboottime": null, + "lastreportedat": null, + "loggedinuser": null, + "machines": [], + "memorypercent": null, + "mtconnectcheckedat": null, + "mtconnectrunning": null, + "pendingreboot": null, + "status": "never", + "trayversion": null, + "uptimedisplay": null, + "uptimeseconds": null } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Get the current state for one endpoint by asset id.", + "example": "curl http://localhost:5001/api/endpoints/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "actionminimums": { + "collect_log": "1.16.0" + }, + "agentcurrent": "1.6.3", + "agentversion": "1.20.0", + "assetid": 2, + "cpupercent": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "credential": { + "credentialprefix": "", + "enrolledvia": "auto", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": "2026-01-01T00:00:00.000000Z", + "reenrollblocked": true, + "reenrollblockedreason": "rollback", + "revokedat": "2026-01-01T00:00:00.000000Z", + "state": "reenrollblocked", + "statelabel": "Re-enroll blocked" + }, + "domain": null, + "endpointstateid": 2, + "hostname": "", + "idleseconds": null, + "lastboottime": null, + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "loggedinuser": null, + "memorypercent": null, + "mtconnectcheckedat": null, + "mtconnectrunning": null, + "pendingreboot": null, + "status": "reporting", + "trayversion": null, + "uptimedisplay": null, + "uptimeseconds": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints//agentupgrade", + "auth": "permission:endpoints.agentupdate", + "params": "path: asset_id (int); body: JSON (fields not yet documented)", + "purpose": "Push the published agent build to one endpoint.", + "example": "curl -X POST http://localhost:5001/api/endpoints/1/agentupgrade -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "action": "run_script", + "target": "script:1" + }, + "responseexample": { + "data": { + "action": "run_script", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "endpointcommandid": 1, + "requestedby": "", + "resultmessage": null, + "status": "pending", + "target": "script:1", + "targetkind": "script" + }, + "message": "Command queued", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints//commands", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Recent commands for one endpoint, newest first (operator view).", + "example": "curl http://localhost:5001/api/endpoints/1/commands -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/endpoints//commands", + "auth": "permission:endpoints.command", + "params": "path: asset_id (int); body: JSON (fields not yet documented)", + "purpose": "Queue an allowlisted command for one endpoint.", + "example": "curl -X POST http://localhost:5001/api/endpoints/1/commands -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "action": "service_status", + "overridereason": "line down, need status", + "policyoverride": true, + "target": "spooler" + }, + "responseexample": { + "data": { + "action": "collect_log", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "endpointcommandid": 1, + "requestedby": "", + "resultmessage": null, + "status": "pending", + "target": "C:\\logs\\app.log", + "targetkind": "logpath" + }, + "message": "Command queued", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints//events", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "List curated Windows events for one endpoint, newest first.", + "example": "curl http://localhost:5001/api/endpoints/1/events -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "eventid", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + } ] - }, - { - "surface": "plugin-employees", - "endpoints": [ + }, + { + "method": "GET", + "path": "/api/endpoints//holdableactions", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Desired-mode actions on this endpoint, with current hold state.", + "example": "curl http://localhost:5001/api/endpoints/1/holdableactions -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "DELETE", - "path": "/api/employees//photo", - "auth": "jwt + role:admin", - "params": "path: sso (int)", - "purpose": "Clear an employee photo and delete the uploaded file. External mode 409s.", - "example": "curl -X DELETE http://localhost:5001/api/employees/1/photo -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/employees//photo", - "auth": "jwt + role:admin", - "params": "path: sso (int); body: JSON (fields not yet documented)", - "purpose": "Upload (or replace) the photo for a self-hosted directory employee.", - "example": "curl -X POST http://localhost:5001/api/employees/1/photo -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/employees/directory", - "auth": "permission:employees.view", - "params": "not documented", - "purpose": "Full self-hosted directory (for the management page).", - "example": "curl http://localhost:5001/api/employees/directory -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/employees/directory", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: employees.create_directory_employee has no docstring.", - "example": "curl -X POST http://localhost:5001/api/employees/directory -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/employees/directory/", - "auth": "jwt + role:admin", - "params": "path: sso (int)", - "purpose": "UNDOCUMENTED: employees.delete_directory_employee has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/employees/directory/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/employees/directory/", - "auth": "jwt + role:admin", - "params": "path: sso (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: employees.update_directory_employee has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/employees/directory/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/employees/directory/import", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Bulk upsert from CSV. Accepts headers SSO,First_Name,Last_Name,Team,Role, Picture (case-insensitive; sso/firstname/... also accepted).", - "example": "curl -X POST http://localhost:5001/api/employees/directory/import -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/employees/lookup", - "auth": "permission:employees.view", - "params": "not documented", - "purpose": "Look up multiple employees by SSO list.", - "example": "curl http://localhost:5001/api/employees/lookup -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/employees/lookup/", - "auth": "permission:employees.view", - "params": "path: sso (string)", - "purpose": "Look up a single employee by SSO.", - "example": "curl http://localhost:5001/api/employees/lookup/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/employees/photo/", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "path: filename (path)", - "purpose": "Serve an uploaded employee photo (public - kiosk cards read it).", - "example": "curl http://localhost:5001/api/employees/photo/example.png" - }, - { - "method": "GET", - "path": "/api/employees/resolve/", - "auth": "permission:employees.view", - "params": "path: sso (string)", - "purpose": "Resolve one SSO to a name and photo, and say HOW.", - "example": "curl http://localhost:5001/api/employees/resolve/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/employees/search", - "auth": "permission:employees.view", - "params": "not documented", - "purpose": "Search employees by name.", - "example": "curl http://localhost:5001/api/employees/search -H \"Authorization: Bearer $TOK\"" + "action": "service_start", + "held": false } - ] - }, - { - "surface": "plugin-endpoints", - "endpoints": [ - { - "method": "GET", - "path": "/api/endpoints", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "List reported endpoint states.", - "example": "curl http://localhost:5001/api/endpoints -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "List reported endpoint states.", - "example": "curl http://localhost:5001/api/endpoints/ -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Get the current state for one endpoint by asset id.", - "example": "curl http://localhost:5001/api/endpoints/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints//agentupgrade", - "auth": "permission:endpoints.agentupdate", - "params": "path: asset_id (int); body: JSON (fields not yet documented)", - "purpose": "Push the published agent build to one endpoint.", - "example": "curl -X POST http://localhost:5001/api/endpoints/1/agentupgrade -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints//commands", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Recent commands for one endpoint, newest first (operator view).", - "example": "curl http://localhost:5001/api/endpoints/1/commands -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints//commands", - "auth": "permission:endpoints.command", - "params": "path: asset_id (int); body: JSON (fields not yet documented)", - "purpose": "Queue an allowlisted command for one endpoint.", - "example": "curl -X POST http://localhost:5001/api/endpoints/1/commands -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints//events", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "List curated Windows events for one endpoint, newest first.", - "example": "curl http://localhost:5001/api/endpoints/1/events -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints//holdableactions", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Desired-mode actions on this endpoint, with current hold state.", - "example": "curl http://localhost:5001/api/endpoints/1/holdableactions -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "DELETE", - "path": "/api/endpoints//lock", - "auth": "permission:endpoints.command", - "params": "path: asset_id (int)", - "purpose": "Lift the quarantine on this endpoint.", - "example": "curl -X DELETE http://localhost:5001/api/endpoints/1/lock -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints//lock", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "The endpoint lock standing on this endpoint, or null.", - "example": "curl http://localhost:5001/api/endpoints/1/lock -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints//lock", - "auth": "permission:endpoints.command", - "params": "path: asset_id (int); body: JSON (fields not yet documented)", - "purpose": "Quarantine this endpoint against non-admin commands.", - "example": "curl -X POST http://localhost:5001/api/endpoints/1/lock -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints//logcollections", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Collected-log history for one endpoint, newest first.", - "example": "curl http://localhost:5001/api/endpoints/1/logcollections -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints//policyholds", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Active break-glass holds for one endpoint.", - "example": "curl http://localhost:5001/api/endpoints/1/policyholds -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints//policyholds", - "auth": "permission:endpoints.command", - "params": "path: asset_id (int); body: JSON (fields not yet documented)", - "purpose": "Deliberately suspend desired-state reconciliation for one or more actions.", - "example": "curl -X POST http://localhost:5001/api/endpoints/1/policyholds -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/endpoints//policyholds/", - "auth": "permission:endpoints.command", - "params": "path: asset_id (int), action (string)", - "purpose": "End a hold early, resuming reconciliation of one action.", - "example": "curl -X DELETE http://localhost:5001/api/endpoints/1/policyholds/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints//scriptruns", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "The last few run_script commands for one endpoint, newest first.", - "example": "curl http://localhost:5001/api/endpoints/1/scriptruns -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/adoptiontool/package", - "auth": "permission:endpoints.agentpackage", - "params": "body: JSON (fields not yet documented)", - "purpose": "Bundle the adoption tool as a downloadable ZIP.", - "example": "curl -X POST http://localhost:5001/api/endpoints/adoptiontool/package -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/endpoints/agentkey", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "Revoke the endpoint agent key: stop all managed-token endpoint traffic.", - "example": "curl -X DELETE http://localhost:5001/api/endpoints/agentkey -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/agentkey", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "Report the endpoint agent key state (no secret).", - "example": "curl http://localhost:5001/api/endpoints/agentkey -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/agentkey/regenerate", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Mint a fresh endpoint agent key, revoking any previous one.", - "example": "curl -X POST http://localhost:5001/api/endpoints/agentkey/regenerate -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/alerts", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "not documented", - "purpose": "Fleet alerts for one endpoint by hostname (collector-token auth).", - "example": "curl http://localhost:5001/api/endpoints/alerts -H \"X-API-Key: $KEY\"" - }, - { - "method": "POST", - "path": "/api/endpoints/alerts//acknowledge", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "path: notification_id (int); body: JSON (fields not yet documented)", - "purpose": "Agent acknowledges a fleet alert (collector-token auth).", - "example": "curl -X POST http://localhost:5001/api/endpoints/alerts/1/acknowledge -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/apppackage/", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "path: appversionid (int)", - "purpose": "Agent-facing installer download (collector-token auth).", - "example": "curl http://localhost:5001/api/endpoints/apppackage/1 -H \"X-API-Key: $KEY\"" - }, - { - "method": "GET", - "path": "/api/endpoints/apppackage/app/", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "path: app_id (int)", - "purpose": "Agent-facing installer download by APP (collector-token auth).", - "example": "curl http://localhost:5001/api/endpoints/apppackage/app/1 -H \"X-API-Key: $KEY\"" - }, - { - "method": "GET", - "path": "/api/endpoints/apppackage/app//", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "path: app_id (int), filename (path)", - "purpose": "Agent-facing installer download by APP (collector-token auth).", - "example": "curl http://localhost:5001/api/endpoints/apppackage/app/1/example.png -H \"X-API-Key: $KEY\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//activity", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "List panel: one chronological feed of what happened to this endpoint.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/activity -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//applications", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Table panel: the installed-software (SBOM) snapshot for this endpoint.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/applications -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//diskhealth", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Physical drive health rows.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/diskhealth -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//hardware", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Keyvalue panel: processor, memory and system chassis inventory.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/hardware -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//interfaces", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Table panel: every hardware NIC the agent last reported.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/interfaces -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//iphistory", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Table panel: every address this asset has held, newest change first.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/iphistory -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//listeners", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Table panel: TCP sockets in LISTEN, with the owning process.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/listeners -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//mappeddrives", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "List panel: mapped network drives with a health badge each.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/mappeddrives -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//osinfo", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Keyvalue panel: operating system, firmware and domain membership.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/osinfo -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//recentevents", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "List panel: the endpoint's most recent curated events, newest first.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/recentevents -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//services", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "List panel: monitored services/processes with a run-state badge per row.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/services -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//status", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Keyvalue panel: the endpoint's current status snapshot.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/status -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//storage", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Tabs panel: volume capacity and physical drive health as two sections.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/storage -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//telemetrymeta", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Lightweight freshness probe for the panels.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/telemetrymeta -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/asset//usercontext", - "auth": "permission:endpoints.view", - "params": "path: asset_id (int)", - "purpose": "Keyvalue panel: session-scoped data from the interactive user probe.", - "example": "curl http://localhost:5001/api/endpoints/asset/1/usercontext -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/collect", - "auth": "api-key (endpoints collector token)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Agent telemetry ingest. Same handler as POST /api/collector/endpoints.", - "example": "curl -X POST http://localhost:5001/api/endpoints/collect -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/endpoints/commands//result", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "path: command_id (int); body: JSON (fields not yet documented)", - "purpose": "Agent reports a claimed command's outcome (collector-token auth).", - "example": "curl -X POST http://localhost:5001/api/endpoints/commands/1/result -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/commands/next", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "not documented", - "purpose": "Agent long-poll: claim the next pending command for a hostname.", - "example": "curl http://localhost:5001/api/endpoints/commands/next -H \"X-API-Key: $KEY\"" - }, - { - "method": "GET", - "path": "/api/endpoints/dashboard/enrollmentpending", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "One queue row while enroll requests wait for an admin, else nothing.", - "example": "curl http://localhost:5001/api/endpoints/dashboard/enrollmentpending -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/dashboard/quiet", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "Endpoints that reported before, then went quiet past the window.", - "example": "curl http://localhost:5001/api/endpoints/dashboard/quiet -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/dashboard/reenrollblocked", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "PCs kept from re-enrolling for more than 7 days.", - "example": "curl http://localhost:5001/api/endpoints/dashboard/reenrollblocked -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/dashboard/stability", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "Endpoints with recent crash/shutdown/corruption events.", - "example": "curl http://localhost:5001/api/endpoints/dashboard/stability -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/dashboard/summary", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "High-level fleet counts for the endpoints dashboard.", - "example": "curl http://localhost:5001/api/endpoints/dashboard/summary -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/enroll", - "auth": "none (per-IP rate limited and capped; a valid fleet key only decides auto-enroll)", - "params": "body: JSON (fields not yet documented)", - "purpose": "A PC asks for its own credential.", - "example": "curl -X POST http://localhost:5001/api/endpoints/enroll -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/enrollment", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "Credential state of every computer, plus pending and recent requests.", - "example": "curl http://localhost:5001/api/endpoints/enrollment -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/enrollment/assets//allow-reenroll", - "auth": "jwt + role:admin", - "params": "path: assetid (int); body: JSON (fields not yet documented)", - "purpose": "Lift a re-enrollment block. The PC enrolls on its next attempt.", - "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/assets/1/allow-reenroll -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/endpoints/enrollment/assets//revoke", - "auth": "jwt + role:admin", - "params": "path: assetid (int); body: JSON (fields not yet documented)", - "purpose": "Un-enroll a PC. Its agent gets CREDENTIAL_INVALID and enrolls again.", - "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/assets/1/revoke -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/enrollment/migration", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "Per-computer readiness to move onto per-PC credentials, plus waves.", - "example": "curl http://localhost:5001/api/endpoints/enrollment/migration -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/enrollment/migration/wave", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Push the agent upgrade to a batch of READY PCs.", - "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/migration/wave -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/endpoints/enrollment/requests//approve", - "auth": "jwt + role:admin", - "params": "path: requestid (int); body: JSON (fields not yet documented)", - "purpose": "Bind a pending request to the asset the admin picked.", - "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/requests/1/approve -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/endpoints/enrollment/requests//reject", - "auth": "jwt + role:admin", - "params": "path: requestid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: endpoints.reject_enroll_request has no docstring.", - "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/requests/1/reject -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "PUT", - "path": "/api/endpoints/enrollment/settings", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Change the enrollment settings.", - "example": "curl -X PUT http://localhost:5001/api/endpoints/enrollment/settings -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/logcollections/", - "auth": "permission:endpoints.updateapp", - "params": "path: collection_id (int)", - "purpose": "One collected log including its content, for the scrollable pane.", - "example": "curl http://localhost:5001/api/endpoints/logcollections/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/logcollections//download", - "auth": "permission:endpoints.updateapp", - "params": "path: collection_id (int)", - "purpose": "Serve a collected log as a file attachment.", - "example": "curl http://localhost:5001/api/endpoints/logcollections/1/download -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/monitors", - "auth": "permission:endpoints.view", - "params": "not documented", - "purpose": "List monitor definitions (shipped and local).", - "example": "curl http://localhost:5001/api/endpoints/monitors -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/monitors", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a user-defined (local) monitor definition.", - "example": "curl -X POST http://localhost:5001/api/endpoints/monitors -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/endpoints/monitors/", - "auth": "jwt + role:admin", - "params": "path: monitor_id (int)", - "purpose": "Delete a local monitor definition. Shipped rows are protected.", - "example": "curl -X DELETE http://localhost:5001/api/endpoints/monitors/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/endpoints/monitors/", - "auth": "jwt + role:admin", - "params": "path: monitor_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a local monitor definition. Shipped rows are read-only.", - "example": "curl -X PUT http://localhost:5001/api/endpoints/monitors/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/monitors/resolve", - "auth": "permission:endpoints.view", - "params": "not documented", - "purpose": "Resolve the monitor set for a PC type (agent runtime fetch).", - "example": "curl http://localhost:5001/api/endpoints/monitors/resolve -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/monitors/resolved", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "not documented", - "purpose": "Agent watch list: the monitors this endpoint should report on.", - "example": "curl http://localhost:5001/api/endpoints/monitors/resolved -H \"X-API-Key: $KEY\"" - }, - { - "method": "POST", - "path": "/api/endpoints/operatorreports", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Agent uploads one operator issue report (collector-token auth).", - "example": "curl -X POST http://localhost:5001/api/endpoints/operatorreports -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/operatorreports//image", - "auth": "permission:endpoints.operatorreports", - "params": "path: operatorreportid (int)", - "purpose": "Serve one operator report's screenshot.", - "example": "curl http://localhost:5001/api/endpoints/operatorreports/1/image -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/panel//operatorreports", - "auth": "permission:endpoints.operatorreports", - "params": "path: asset_id (int)", - "purpose": "Operator Reports panel: this PC's recent operator issue reports.", - "example": "curl http://localhost:5001/api/endpoints/panel/1/operatorreports -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/scriptbody/", - "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", - "params": "path: script_id (int)", - "purpose": "Agent-facing script body download (collector-token auth).", - "example": "curl http://localhost:5001/api/endpoints/scriptbody/1 -H \"X-API-Key: $KEY\"" - }, - { - "method": "GET", - "path": "/api/endpoints/settings/server-cert", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "Get details about the current server certificate.", - "example": "curl http://localhost:5001/api/endpoints/settings/server-cert -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/settings/server-cert/download", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "The PUBLIC server certificate as a DER .cer file, never the key.", - "example": "curl http://localhost:5001/api/endpoints/settings/server-cert/download -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/settings/server-cert/generate", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Generate a new self-signed server certificate.", - "example": "curl -X POST http://localhost:5001/api/endpoints/settings/server-cert/generate -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/settings/server-cert/live", - "auth": "permission:endpoints.fleet", - "params": "not documented", - "purpose": "The certificate PCs actually receive from this site's public address.", - "example": "curl http://localhost:5001/api/endpoints/settings/server-cert/live -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/settings/server-cert/upload", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Upload a new server certificate and private key.", - "example": "curl -X POST http://localhost:5001/api/endpoints/settings/server-cert/upload -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/siteagent", - "auth": "permission:endpoints.agentpackage", - "params": "not documented", - "purpose": "Report whether the site agent build has a prebuilt binary staged.", - "example": "curl http://localhost:5001/api/endpoints/siteagent -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/endpoints/siteagent/binaries/", - "auth": "permission:endpoints.agentpackage", - "params": "path: binkey (string)", - "purpose": "List staged versions for a binary (agent or tray), newest first.", - "example": "curl http://localhost:5001/api/endpoints/siteagent/binaries/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/siteagent/binaries/", - "auth": "permission:endpoints.agentpackage", - "params": "path: binkey (string); body: JSON (fields not yet documented)", - "purpose": "Stage an uploaded binary as a new version.", - "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/binaries/x -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/endpoints/siteagent/binaries//adopt", - "auth": "permission:endpoints.agentpackage", - "params": "path: binkey (string); body: JSON (fields not yet documented)", - "purpose": "Adopt the unmanaged legacy flat file into the version store.", - "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/binaries/x/adopt -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "PUT", - "path": "/api/endpoints/siteagent/binaries//current", - "auth": "permission:endpoints.agentpackage", - "params": "path: binkey (string); body: JSON (fields not yet documented)", - "purpose": "Point 'current' at an already-staged version (roll back or forward).", - "example": "curl -X PUT http://localhost:5001/api/endpoints/siteagent/binaries/x/current -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/endpoints/siteagent/binaries//detect", - "auth": "permission:endpoints.agentpackage", - "params": "path: binkey (string); body: JSON (fields not yet documented)", - "purpose": "Read the PE file version of an uploaded EXE without staging it.", - "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/binaries/x/detect -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/endpoints/siteagent/bootstrap.ps1", - "auth": "api-key (single-use bootstrap token in the X-Endpoint-Bootstrap-Token header, or ?t= while that is enabled; per-IP rate limited, 404 when not usable)", - "params": "not documented", - "purpose": "The PowerShell the one-line command downloads, runs and deletes.", - "example": "curl http://localhost:5001/api/endpoints/siteagent/bootstrap.ps1" - }, - { - "method": "GET", - "path": "/api/endpoints/siteagent/bootstrap/package", - "auth": "api-key (single-use bootstrap token in the X-Endpoint-Bootstrap-Token header, or ?t= while that is enabled; per-IP rate limited, 404 when not usable)", - "params": "not documented", - "purpose": "The keyless agent package the bootstrap script installs.", - "example": "curl http://localhost:5001/api/endpoints/siteagent/bootstrap/package" - }, - { - "method": "GET", - "path": "/api/endpoints/siteagent/bootstrap/tokens", - "auth": "jwt + role:admin", - "params": "not documented", - "purpose": "Every bootstrap token, newest first. Never a secret.", - "example": "curl http://localhost:5001/api/endpoints/siteagent/bootstrap/tokens -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/endpoints/siteagent/bootstrap/tokens", - "auth": "jwt + role:admin", - "params": "body: JSON (fields not yet documented)", - "purpose": "Mint one short-lived bootstrap token. The secret is returned ONCE.", - "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/bootstrap/tokens -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/endpoints/siteagent/bootstrap/tokens//revoke", - "auth": "jwt + role:admin", - "params": "path: tokenid (int); body: JSON (fields not yet documented)", - "purpose": "Kill a bootstrap token now. Already-revoked is a no-op, not an error.", - "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/bootstrap/tokens/1/revoke -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/endpoints/siteagent/package", - "auth": "permission:endpoints.agentpackage", - "params": "body: JSON (fields not yet documented)", - "purpose": "Bundle the site agent as a downloadable ZIP.", - "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/package -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "DELETE", + "path": "/api/endpoints//lock", + "auth": "permission:endpoints.command", + "params": "path: asset_id (int)", + "purpose": "Lift the quarantine on this endpoint.", + "example": "curl -X DELETE http://localhost:5001/api/endpoints/1/lock -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints//lock", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "The endpoint lock standing on this endpoint, or null.", + "example": "curl http://localhost:5001/api/endpoints/1/lock -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "assetid": 1, + "endpointlockid": 1, + "lockedat": "2026-01-01T00:00:00.000000Z", + "lockedbyuserid": 1, + "lockedbyusername": "", + "reason": "visible to all", + "releasedat": null, + "releasedbyusername": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints//lock", + "auth": "permission:endpoints.command", + "params": "path: asset_id (int); body: JSON (fields not yet documented)", + "purpose": "Quarantine this endpoint against non-admin commands.", + "example": "curl -X POST http://localhost:5001/api/endpoints/1/lock -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "reason": "locked but still reconciled" + }, + "responseexample": { + "data": { + "assetid": 1, + "endpointlockid": 1, + "lockedat": "2026-01-01T00:00:00.000000Z", + "lockedbyuserid": 1, + "lockedbyusername": "", + "reason": "locked but still reconciled", + "releasedat": null, + "releasedbyusername": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints//logcollections", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Collected-log history for one endpoint, newest first.", + "example": "curl http://localhost:5001/api/endpoints/1/logcollections -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints//policyholds", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Active break-glass holds for one endpoint.", + "example": "curl http://localhost:5001/api/endpoints/1/policyholds -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ + { + "action": "service_stop", + "createdbyusername": "", + "expiresat": "2026-01-01T00:00:00.000000", + "reason": "vendor on site" } - ] - }, - { - "surface": "plugin-geenforce", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints//policyholds", + "auth": "permission:endpoints.command", + "params": "path: asset_id (int); body: JSON (fields not yet documented)", + "purpose": "Deliberately suspend desired-state reconciliation for one or more actions.", + "example": "curl -X POST http://localhost:5001/api/endpoints/1/policyholds -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "actions": [ + "service_start", + "service_stop" + ], + "minutes": 60, + "reason": "stripping the enclosure" + }, + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/geenforce/applications", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "not documented", - "purpose": "The core Applications catalog (id + name) for the curated entry->app link picker in the entry editor.", - "example": "curl http://localhost:5001/api/geenforce/applications -H \"Authorization: Bearer $TOK\"" + "action": "service_stop", + "createdbyusername": "", + "expiresat": "2026-01-01T00:00:00.000000", + "reason": "stripping the enclosure" }, { - "method": "GET", - "path": "/api/geenforce/config", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "not documented", - "purpose": "Plugin config: the on-share export root + the client IP allowlist.", - "example": "curl http://localhost:5001/api/geenforce/config -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/geenforce/config", - "auth": "permission:geenforce.publish", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: geenforce.put_config has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/geenforce/config -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/geenforce/dashboard/failures", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "not documented", - "purpose": "Entries that FAILED on their PC's most recent enforcement cycle.", - "example": "curl http://localhost:5001/api/geenforce/dashboard/failures -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "DELETE", - "path": "/api/geenforce/entries/", - "auth": "permission:geenforce.manage", - "params": "path: entryid (int)", - "purpose": "UNDOCUMENTED: geenforce.delete_entry has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/geenforce/entries/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/geenforce/entries/", - "auth": "permission:geenforce.manage", - "params": "path: entryid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: geenforce.update_entry has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/geenforce/entries/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/geenforce/entries//payload", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: entryid (int)", - "purpose": "Return the stored inline payload bytes for an entry (404 if none).", - "example": "curl http://localhost:5001/api/geenforce/entries/1/payload -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/geenforce/entries//payload", - "auth": "permission:geenforce.publish", - "params": "path: entryid (int); body: JSON (fields not yet documented)", - "purpose": "Store an inline payload (<= 1 MB) for an entry and point the entry at it.", - "example": "curl -X POST http://localhost:5001/api/geenforce/entries/1/payload -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/geenforce/manifest", - "auth": "api-key (geenforce fetch token, or the IP allowlist)", - "params": "not documented", - "purpose": "Serve the current published manifest for a scope (fat-client: full scope).", - "example": "curl http://localhost:5001/api/geenforce/manifest -H \"X-API-Key: $KEY\"" - }, - { - "method": "GET", - "path": "/api/geenforce/payload/", - "auth": "api-key (geenforce fetch token, or the IP allowlist)", - "params": "path: sha256 (string)", - "purpose": "Serve a payload blob by content hash over HTTPS.", - "example": "curl http://localhost:5001/api/geenforce/payload/x -H \"X-API-Key: $KEY\"" - }, - { - "method": "POST", - "path": "/api/geenforce/report", - "auth": "api-key (geenforce report token)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Record one PC's enforcement cycle: applied version (did it receive the update?) + per-entry self-heal outcomes (installed/skipped/failed).", - "example": "curl -X POST http://localhost:5001/api/geenforce/report -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/geenforce/reports", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "not documented", - "purpose": "Latest enforcement report per PC (fleet compliance view).", - "example": "curl http://localhost:5001/api/geenforce/reports -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/geenforce/reports/", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: reportid (int)", - "purpose": "One report with per-entry outcomes (self-heal / failure detail).", - "example": "curl http://localhost:5001/api/geenforce/reports/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/geenforce/scopes", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "not documented", - "purpose": "List imaging PC-type scopes with entry + published-version counts.", - "example": "curl http://localhost:5001/api/geenforce/scopes -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/geenforce/scopes", - "auth": "permission:geenforce.manage", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: geenforce.create_scope has no docstring.", - "example": "curl -X POST http://localhost:5001/api/geenforce/scopes -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/geenforce/scopes/", - "auth": "permission:geenforce.manage", - "params": "path: scopeid (int)", - "purpose": "UNDOCUMENTED: geenforce.delete_scope has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/geenforce/scopes/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/geenforce/scopes/", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: scopeid (int)", - "purpose": "UNDOCUMENTED: geenforce.get_scope has no docstring.", - "example": "curl http://localhost:5001/api/geenforce/scopes/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/geenforce/scopes/", - "auth": "permission:geenforce.manage", - "params": "path: scopeid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: geenforce.update_scope has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/geenforce/scopes/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/geenforce/scopes//compliance", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: scopeid (int)", - "purpose": "Fleet-install coverage per app-linked entry (from collected PC data).", - "example": "curl http://localhost:5001/api/geenforce/scopes/1/compliance -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/geenforce/scopes//entries", - "auth": "permission:geenforce.manage", - "params": "path: scopeid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: geenforce.create_entry has no docstring.", - "example": "curl -X POST http://localhost:5001/api/geenforce/scopes/1/entries -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "PUT", - "path": "/api/geenforce/scopes//entries/reorder", - "auth": "permission:geenforce.manage", - "params": "path: scopeid (int); body: JSON (fields not yet documented)", - "purpose": "Set entry order from a list of entryids (the ordering contract).", - "example": "curl -X PUT http://localhost:5001/api/geenforce/scopes/1/entries/reorder -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/geenforce/scopes//export-share", - "auth": "permission:geenforce.publish", - "params": "path: scopeid (int); body: JSON (fields not yet documented)", - "purpose": "Write the scope's current published JSON to the configured share root (backing up the old file to _meta/history first).", - "example": "curl -X POST http://localhost:5001/api/geenforce/scopes/1/export-share -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/geenforce/scopes//preview", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: scopeid (int)", - "purpose": "Render the DRAFT manifest JSON a publish would freeze (review before ship).", - "example": "curl http://localhost:5001/api/geenforce/scopes/1/preview -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/geenforce/scopes//publish", - "auth": "permission:geenforce.publish", - "params": "path: scopeid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: geenforce.publish_scope_route has no docstring.", - "example": "curl -X POST http://localhost:5001/api/geenforce/scopes/1/publish -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/geenforce/scopes//publish-preflight", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: scopeid (int)", - "purpose": "Would publishing this scope outrun the fleet's enforcer lib?", - "example": "curl http://localhost:5001/api/geenforce/scopes/1/publish-preflight -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/geenforce/scopes//rollback", - "auth": "permission:geenforce.publish", - "params": "path: scopeid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: geenforce.rollback_scope_route has no docstring.", - "example": "curl -X POST http://localhost:5001/api/geenforce/scopes/1/rollback -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/geenforce/scopes//simulate", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: scopeid (int)", - "purpose": "Which draft entries apply to a given machine profile, and why the rest are filtered out (reuses the engine-mirror filters).", - "example": "curl http://localhost:5001/api/geenforce/scopes/1/simulate -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/geenforce/scopes//versions", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: scopeid (int)", - "purpose": "UNDOCUMENTED: geenforce.list_versions has no docstring.", - "example": "curl http://localhost:5001/api/geenforce/scopes/1/versions -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/geenforce/scopes//versions/", - "auth": "permission:geenforce.view or geenforce.manage", - "params": "path: scopeid (int), versionnumber (int)", - "purpose": "UNDOCUMENTED: geenforce.get_version has no docstring.", - "example": "curl http://localhost:5001/api/geenforce/scopes/1/versions/1 -H \"Authorization: Bearer $TOK\"" + "action": "service_start", + "createdbyusername": "", + "expiresat": "2026-01-01T00:00:00.000000", + "reason": "stripping the enclosure" } - ] - }, - { - "surface": "plugin-guides", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/endpoints//policyholds/", + "auth": "permission:endpoints.command", + "params": "path: asset_id (int), action (string)", + "purpose": "End a hold early, resuming reconciliation of one action.", + "example": "curl -X DELETE http://localhost:5001/api/endpoints/1/policyholds/x -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints//scriptruns", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "The last few run_script commands for one endpoint, newest first.", + "example": "curl http://localhost:5001/api/endpoints/1/scriptruns -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "limit", + "type": "integer", + "required": false, + "default": 5 + } + ], + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/guides", - "auth": "permission:guides.view", - "params": "not documented", - "purpose": "Published guides, plus the caller's own drafts if they can author.", - "example": "curl http://localhost:5001/api/guides -H \"Authorization: Bearer $TOK\"" + "action": "run_script", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00Z", + "endpointcommandid": 6, + "requestedby": "", + "resultdetail": null, + "resultmessage": null, + "scriptname": "test-open-notepad", + "status": "succeeded", + "target": "script:1", + "targetkind": null }, { - "method": "POST", - "path": "/api/guides", - "auth": "permission:guides.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: guides.create_guide has no docstring.", - "example": "curl -X POST http://localhost:5001/api/guides -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "action": "run_script", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00Z", + "endpointcommandid": 5, + "requestedby": "", + "resultdetail": null, + "resultmessage": null, + "scriptname": "test-open-notepad", + "status": "succeeded", + "target": "script:1", + "targetkind": null }, { - "method": "DELETE", - "path": "/api/guides/", - "auth": "permission:guides.delete", - "params": "path: guideid (int)", - "purpose": "UNDOCUMENTED: guides.delete_guide has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/guides/1 -H \"Authorization: Bearer $TOK\"" + "action": "run_script", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00Z", + "endpointcommandid": 4, + "requestedby": "", + "resultdetail": null, + "resultmessage": null, + "scriptname": "test-open-notepad", + "status": "succeeded", + "target": "script:1", + "targetkind": null }, - { - "method": "PUT", - "path": "/api/guides/", - "auth": "permission:guides.view", - "params": "path: guideid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: guides.update_guide has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/guides/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/adoptiontool/package", + "auth": "permission:endpoints.agentpackage", + "params": "body: JSON (fields not yet documented)", + "purpose": "Bundle the adoption tool as a downloadable ZIP.", + "example": "curl -X POST http://localhost:5001/api/endpoints/adoptiontool/package -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/endpoints/agentkey", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "Revoke the endpoint agent key: stop all managed-token endpoint traffic.", + "example": "curl -X DELETE http://localhost:5001/api/endpoints/agentkey -H \"Authorization: Bearer $TOK\"", + "requestexample": {}, + "responseexample": { + "data": { + "envkeyfallback": true, + "key": null, + "provisioned": false, + "revoked": 0 + }, + "message": "Endpoint agent key revoked", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/agentkey", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "Report the endpoint agent key state (no secret).", + "example": "curl http://localhost:5001/api/endpoints/agentkey -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/endpoints/agentkey/regenerate", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Mint a fresh endpoint agent key, revoking any previous one.", + "example": "curl -X POST http://localhost:5001/api/endpoints/agentkey/regenerate -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": {}, + "responseexample": { + "data": { + "envkeyfallback": false, + "key": { + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "Endpoint agent key", + "resourcescopes": null, + "scopes": [ + "collector.ingest.endpoints" + ], + "tokenid": 1, + "tokenprefix": "", + "userid": 1 }, + "provisioned": true, + "secret": "", + "warning": "Save this key now. It will not be shown again. Configure it as the agent X-API-Key." + }, + "message": "Endpoint agent key generated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/alerts", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "not documented", + "purpose": "Fleet alerts for one endpoint by hostname (collector-token auth).", + "example": "curl http://localhost:5001/api/endpoints/alerts -H \"X-API-Key: $KEY\"", + "queryparams": [ + { + "name": "hostname", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "POST", - "path": "/api/guides//publish", - "auth": "permission:guides.publish", - "params": "path: guideid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: guides.publish_guide has no docstring.", - "example": "curl -X POST http://localhost:5001/api/guides/1/publish -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/guides//restore/", - "auth": "permission:guides.view", - "params": "path: guideid (int), revisionid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: guides.restore_revision has no docstring.", - "example": "curl -X POST http://localhost:5001/api/guides/1/restore/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/guides//revisions", - "auth": "permission:guides.view", - "params": "path: guideid (int)", - "purpose": "UNDOCUMENTED: guides.list_revisions has no docstring.", - "example": "curl http://localhost:5001/api/guides/1/revisions -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/guides//unpublish", - "auth": "permission:guides.publish", - "params": "path: guideid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: guides.unpublish_guide has no docstring.", - "example": "curl -X POST http://localhost:5001/api/guides/1/unpublish -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/guides//working", - "auth": "permission:guides.view", - "params": "path: guideid (int)", - "purpose": "The working copy, for the editor.", - "example": "curl http://localhost:5001/api/guides/1/working -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/guides/", - "auth": "permission:guides.view", - "params": "path: slug (string)", - "purpose": "What a reader gets: the published revision.", - "example": "curl http://localhost:5001/api/guides/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/guides/images", - "auth": "permission:guides.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Take a pasted or dropped image.", - "example": "curl -X POST http://localhost:5001/api/guides/images -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/guides/images/", - "auth": "permission:guides.view", - "params": "path: imageid (int)", - "purpose": "The image itself, under the same rule as the guide that holds it.", - "example": "curl http://localhost:5001/api/guides/images/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/guides/revisions/", - "auth": "permission:guides.view", - "params": "path: revisionid (int)", - "purpose": "One revision by id.", - "example": "curl http://localhost:5001/api/guides/revisions/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/guides/tags", - "auth": "permission:guides.view", - "params": "not documented", - "purpose": "Every tag in use, with a count, for the filter chips.", - "example": "curl http://localhost:5001/api/guides/tags -H \"Authorization: Bearer $TOK\"" + "message": "Scheduled maintenance at 3:30 PM", + "notificationId": 1, + "notificationid": 1, + "timeout": 0, + "title": "Scheduled maintenance at 3:30 PM", + "type": "Fleet Alert", + "typeColor": "#ffc107", + "typecolor": "#ffc107" } - ] - }, - { - "surface": "plugin-knowledgebase", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/alerts//acknowledge", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "path: notification_id (int); body: JSON (fields not yet documented)", + "purpose": "Agent acknowledges a fleet alert (collector-token auth).", + "example": "curl -X POST http://localhost:5001/api/endpoints/alerts/1/acknowledge -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "assetid": 1, + "hostname": "" + }, + "responseexample": { + "data": { + "acknowledged": true + }, + "message": "Alert already acknowledged", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/apppackage/", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "path: appversionid (int)", + "purpose": "Agent-facing installer download (collector-token auth).", + "example": "curl http://localhost:5001/api/endpoints/apppackage/1 -H \"X-API-Key: $KEY\"" + }, + { + "method": "GET", + "path": "/api/endpoints/apppackage/app/", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "path: app_id (int)", + "purpose": "Agent-facing installer download by APP (collector-token auth).", + "example": "curl http://localhost:5001/api/endpoints/apppackage/app/1 -H \"X-API-Key: $KEY\"" + }, + { + "method": "GET", + "path": "/api/endpoints/apppackage/app//", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "path: app_id (int), filename (path)", + "purpose": "Agent-facing installer download by APP (collector-token auth).", + "example": "curl http://localhost:5001/api/endpoints/apppackage/app/1/example.png -H \"X-API-Key: $KEY\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//activity", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "List panel: one chronological feed of what happened to this endpoint.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/activity -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//applications", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Table panel: the installed-software (SBOM) snapshot for this endpoint.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/applications -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//diskhealth", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Physical drive health rows.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/diskhealth -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//hardware", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Keyvalue panel: processor, memory and system chassis inventory.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/hardware -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//interfaces", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Table panel: every hardware NIC the agent last reported.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/interfaces -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//iphistory", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Table panel: every address this asset has held, newest change first.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/iphistory -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//listeners", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Table panel: TCP sockets in LISTEN, with the owning process.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/listeners -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//mappeddrives", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "List panel: mapped network drives with a health badge each.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/mappeddrives -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//osinfo", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Keyvalue panel: operating system, firmware and domain membership.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/osinfo -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//recentevents", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "List panel: the endpoint's most recent curated events, newest first.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/recentevents -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//services", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "List panel: monitored services/processes with a run-state badge per row.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/services -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/knowledgebase", - "auth": "permission:kb.view", - "params": "not documented", - "purpose": "List all knowledge base articles.", - "example": "curl http://localhost:5001/api/knowledgebase -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/knowledgebase", - "auth": "permission:kb.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new knowledge base article.", - "example": "curl -X POST http://localhost:5001/api/knowledgebase -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/knowledgebase/", - "auth": "permission:kb.delete", - "params": "path: link_id (int)", - "purpose": "Delete (deactivate) a knowledge base article.", - "example": "curl -X DELETE http://localhost:5001/api/knowledgebase/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/knowledgebase/", - "auth": "permission:kb.view", - "params": "path: link_id (int)", - "purpose": "Get a single knowledge base article.", - "example": "curl http://localhost:5001/api/knowledgebase/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/knowledgebase/", - "auth": "permission:kb.edit", - "params": "path: link_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a knowledge base article.", - "example": "curl -X PUT http://localhost:5001/api/knowledgebase/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/knowledgebase//click", - "auth": "permission:kb.view", - "params": "path: link_id (int); body: JSON (fields not yet documented)", - "purpose": "Increment the click counter for an article the caller is allowed to read.", - "example": "curl -X POST http://localhost:5001/api/knowledgebase/1/click -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/knowledgebase/stats", - "auth": "permission:kb.view", - "params": "not documented", - "purpose": "Get knowledge base statistics.", - "example": "curl http://localhost:5001/api/knowledgebase/stats -H \"Authorization: Bearer $TOK\"" + "action": { + "running": false, + "start": "process_start", + "status": "process_status", + "stop": "process_stop", + "target": "dncMain.exe", + "targetkind": "process" + }, + "drift": true, + "kind": "process", + "name": "eDNC", + "statecolor": "gray", + "statelabel": "Unknown" } - ] - }, - { - "surface": "plugin-machines", - "endpoints": [ - { - "method": "GET", - "path": "/api/machines", - "auth": "permission:machines.view", - "params": "not documented", - "purpose": "List all machines with filtering and pagination.", - "example": "curl http://localhost:5001/api/machines -H \"Authorization: Bearer $TOK\"" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/asset//status", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Keyvalue panel: the endpoint's current status snapshot.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/status -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "agentbehind": false, + "agentcurrent": "1.6.3", + "agentversion": "1.20.0", + "credential": { + "credentialprefix": "", + "enrolledvia": "auto", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": "2026-01-01T00:00:00.000000Z", + "reenrollblocked": true, + "reenrollblockedreason": "rollback", + "revokedat": "2026-01-01T00:00:00.000000Z", + "state": "reenrollblocked", + "statelabel": "Re-enroll blocked" }, + "fields": [ + { + "label": "Agent", + "mono": true, + "value": "1.20.0" + }, + { + "format": "datetime", + "label": "Last reported", + "mono": false, + "value": "2026-01-01T00:00:00.000000Z" + }, + { + "label": "Credential", + "mono": false, + "value": "Re-enroll blocked" + }, + "" + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/asset//storage", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Tabs panel: volume capacity and physical drive health as two sections.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/storage -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//telemetrymeta", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Lightweight freshness probe for the panels.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/telemetrymeta -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/asset//usercontext", + "auth": "permission:endpoints.view", + "params": "path: asset_id (int)", + "purpose": "Keyvalue panel: session-scoped data from the interactive user probe.", + "example": "curl http://localhost:5001/api/endpoints/asset/1/usercontext -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/endpoints/collect", + "auth": "api-key (endpoints collector token)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Agent telemetry ingest. Same handler as POST /api/collector/endpoints.", + "example": "curl -X POST http://localhost:5001/api/endpoints/collect -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "agentversion": "1.20.0", + "hostname": "" + }, + "responseexample": { + "data": { + "action": "created", + "assetid": 1, + "identityvalue": "BAY-01", + "status": "ok", + "warnings": [] + }, + "message": "endpoints collector created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/commands//result", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "path: command_id (int); body: JSON (fields not yet documented)", + "purpose": "Agent reports a claimed command's outcome (collector-token auth).", + "example": "curl -X POST http://localhost:5001/api/endpoints/commands/1/result -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "queryparams": [ + { + "name": "hostname", + "type": "string", + "required": false + } + ], + "requestexample": { + "succeeded": true + }, + "responseexample": { + "data": { + "action": "mtconnect_status", + "assetid": 1, + "claimedat": null, + "completedat": "2026-01-01T00:00:00.000000Z", + "createdat": "2026-01-01T00:00:00.000000Z", + "endpointcommandid": 1, + "requestedby": "", + "resultmessage": null, + "status": "succeeded", + "target": null, + "targetkind": null + }, + "message": "Result recorded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/commands/next", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "not documented", + "purpose": "Agent long-poll: claim the next pending command for a hostname.", + "example": "curl http://localhost:5001/api/endpoints/commands/next -H \"X-API-Key: $KEY\"", + "queryparams": [ + { + "name": "hostname", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "action": "mtconnect_status", + "endpointcommandid": 1, + "target": null, + "targetkind": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/dashboard/enrollmentpending", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "One queue row while enroll requests wait for an admin, else nothing.", + "example": "curl http://localhost:5001/api/endpoints/dashboard/enrollmentpending -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "POST", - "path": "/api/machines", - "auth": "permission:machines.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create new machine (creates both Asset and Machine records).", - "example": "curl -X POST http://localhost:5001/api/machines -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/machines/", - "auth": "permission:machines.delete", - "params": "path: machine_id (int)", - "purpose": "Delete (soft delete) machine.", - "example": "curl -X DELETE http://localhost:5001/api/machines/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/machines/", - "auth": "permission:machines.view", - "params": "path: machine_id (int)", - "purpose": "Get a single machine item with full details.", - "example": "curl http://localhost:5001/api/machines/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/machines/", - "auth": "permission:machines.edit", - "params": "path: machine_id (int); body: JSON (fields not yet documented)", - "purpose": "Update machine (both Asset and Machine records).", - "example": "curl -X PUT http://localhost:5001/api/machines/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/machines/by-asset/", - "auth": "permission:machines.view", - "params": "path: asset_id (int)", - "purpose": "Get machine data by asset ID.", - "example": "curl http://localhost:5001/api/machines/by-asset/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/machines/dashboard/outofservice", - "auth": "permission:machines.view", - "params": "not documented", - "purpose": "Machines whose status says they are not running.", - "example": "curl http://localhost:5001/api/machines/dashboard/outofservice -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/machines/dashboard/summary", - "auth": "permission:machines.view", - "params": "not documented", - "purpose": "Get machine dashboard summary data.", - "example": "curl http://localhost:5001/api/machines/dashboard/summary -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/machines/types", - "auth": "permission:machines.view", - "params": "not documented", - "purpose": "List all machine types.", - "example": "curl http://localhost:5001/api/machines/types -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/machines/types", - "auth": "permission:machines.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new machine type.", - "example": "curl -X POST http://localhost:5001/api/machines/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/machines/types/", - "auth": "permission:machines.delete", - "params": "path: type_id (int)", - "purpose": "Delete a machine type. Refused if any asset still uses it.", - "example": "curl -X DELETE http://localhost:5001/api/machines/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/machines/types/", - "auth": "permission:machines.view", - "params": "path: type_id (int)", - "purpose": "Get a single machine type.", - "example": "curl http://localhost:5001/api/machines/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/machines/types/", - "auth": "permission:machines.edit", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a machine type.", - "example": "curl -X PUT http://localhost:5001/api/machines/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "pendingcount": 2, + "summary": "2 PCs waiting for enrollment approval" } - ] - }, - { - "surface": "plugin-measuringtools", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/dashboard/quiet", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "Endpoints that reported before, then went quiet past the window.", + "example": "curl http://localhost:5001/api/endpoints/dashboard/quiet -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/dashboard/reenrollblocked", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "PCs kept from re-enrolling for more than 7 days.", + "example": "curl http://localhost:5001/api/endpoints/dashboard/reenrollblocked -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/measuringtools", - "auth": "permission:measuringtools.view", - "params": "not documented", - "purpose": "List measuring tools with filters + pagination.", - "example": "curl http://localhost:5001/api/measuringtools -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/measuringtools", - "auth": "permission:measuringtools.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a measuring tool: one Asset core row + one extension row.", - "example": "curl -X POST http://localhost:5001/api/measuringtools -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/measuringtools/", - "auth": "permission:measuringtools.delete", - "params": "path: tool_id (int)", - "purpose": "Soft delete a measuring tool (deactivates its asset).", - "example": "curl -X DELETE http://localhost:5001/api/measuringtools/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/measuringtools/", - "auth": "permission:measuringtools.view", - "params": "path: tool_id (int)", - "purpose": "Get one measuring tool (asset core merged with the extension).", - "example": "curl http://localhost:5001/api/measuringtools/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/measuringtools/", - "auth": "permission:measuringtools.edit", - "params": "path: tool_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a measuring tool (asset core fields + extension in one payload).", - "example": "curl -X PUT http://localhost:5001/api/measuringtools/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/measuringtools/by-asset/", - "auth": "permission:measuringtools.view", - "params": "path: asset_id (int)", - "purpose": "Get a measuring tool by its core asset id.", - "example": "curl http://localhost:5001/api/measuringtools/by-asset/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/measuringtools/map-overlay", - "auth": "permission:measuringtools.view", - "params": "not documented", - "purpose": "Calibration-status overlay for active measuring tools.", - "example": "curl http://localhost:5001/api/measuringtools/map-overlay -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/measuringtools/report/calibration", - "auth": "permission:measuringtools.view", - "params": "not documented", - "purpose": "Counts + lists bucketed by derived calibration status.", - "example": "curl http://localhost:5001/api/measuringtools/report/calibration -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/measuringtools/types", - "auth": "permission:measuringtools.view", - "params": "not documented", - "purpose": "List measuring-tool types.", - "example": "curl http://localhost:5001/api/measuringtools/types -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/measuringtools/types", - "auth": "permission:measuringtools.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a measuring-tool type (reactivates a soft-deleted same-named one).", - "example": "curl -X POST http://localhost:5001/api/measuringtools/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/measuringtools/types/", - "auth": "permission:measuringtools.delete", - "params": "path: type_id (int)", - "purpose": "Delete a measuring-tool type. Refused if any tool still uses it.", - "example": "curl -X DELETE http://localhost:5001/api/measuringtools/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/measuringtools/types/", - "auth": "permission:measuringtools.view", - "params": "path: type_id (int)", - "purpose": "Get one measuring-tool type.", - "example": "curl http://localhost:5001/api/measuringtools/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/measuringtools/types/", - "auth": "permission:measuringtools.edit", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a measuring-tool type.", - "example": "curl -X PUT http://localhost:5001/api/measuringtools/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "assetid": 2, + "blockeddays": 9, + "computerid": 2, + "hostname": "", + "reason": "rollback" } - ] - }, - { - "surface": "plugin-network", - "endpoints": [ - { - "method": "GET", - "path": "/api/network", - "auth": "permission:network.view", - "params": "not documented", - "purpose": "List all network devices with filtering and pagination.", - "example": "curl http://localhost:5001/api/network -H \"Authorization: Bearer $TOK\"" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/dashboard/stability", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "Endpoints with recent crash/shutdown/corruption events.", + "example": "curl http://localhost:5001/api/endpoints/dashboard/stability -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/dashboard/summary", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "High-level fleet counts for the endpoints dashboard.", + "example": "curl http://localhost:5001/api/endpoints/dashboard/summary -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/endpoints/enroll", + "auth": "none (per-IP rate limited and capped; a valid fleet key only decides auto-enroll)", + "params": "body: JSON (fields not yet documented)", + "purpose": "A PC asks for its own credential.", + "example": "curl -X POST http://localhost:5001/api/endpoints/enroll -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "agentversion": "1.20.0", + "deviceid": null, + "enrollnonce": "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", + "hostname": "", + "serialnumber": "" + }, + "responseexample": { + "data": { + "assetid": 1, + "credential": "", + "status": "enrolled" + }, + "message": "Endpoint enrolled", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/enrollment", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "Credential state of every computer, plus pending and recent requests.", + "example": "curl http://localhost:5001/api/endpoints/enrollment -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "state", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "computers": [ + { + "assetid": 1, + "credentialprefix": "", + "enrolledvia": "auto", + "hostname": "", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "reenrollblocked": false, + "reenrollblockedreason": null, + "serialnumber": "", + "state": "enrolled" + }, + { + "assetid": 2, + "credentialprefix": "", + "enrolledvia": null, + "hostname": "", + "issuedat": null, + "lastusedat": null, + "reenrollblocked": false, + "reenrollblockedreason": null, + "serialnumber": "", + "state": "notenrolled" + }, + { + "assetid": 3, + "credentialprefix": "", + "enrolledvia": null, + "hostname": "", + "issuedat": null, + "lastusedat": null, + "reenrollblocked": false, + "reenrollblockedreason": null, + "serialnumber": "", + "state": "pending" + } + ], + "counts": { + "enrolled": 1, + "notenrolled": 1, + "pending": 1, + "pendingcomputers": 1 }, - { - "method": "POST", - "path": "/api/network", - "auth": "permission:network.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create new network device (creates both Asset and NetworkDevice records).", - "example": "curl -X POST http://localhost:5001/api/network -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/network/", - "auth": "permission:network.delete", - "params": "path: device_id (int)", - "purpose": "Delete (soft delete) network device.", - "example": "curl -X DELETE http://localhost:5001/api/network/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/network/", - "auth": "permission:network.view", - "params": "path: device_id (int)", - "purpose": "Get a single network device with full details.", - "example": "curl http://localhost:5001/api/network/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/network/", - "auth": "permission:network.edit", - "params": "path: device_id (int); body: JSON (fields not yet documented)", - "purpose": "Update network device (both Asset and NetworkDevice records).", - "example": "curl -X PUT http://localhost:5001/api/network/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/network/by-asset/", - "auth": "permission:network.view", - "params": "path: asset_id (int)", - "purpose": "Get network device data by asset ID.", - "example": "curl http://localhost:5001/api/network/by-asset/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/network/by-hostname/", - "auth": "permission:network.view", - "params": "path: hostname (string)", - "purpose": "Get network device by hostname.", - "example": "curl http://localhost:5001/api/network/by-hostname/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/network/dashboard/summary", - "auth": "permission:network.view", - "params": "not documented", - "purpose": "Get network device dashboard summary data.", - "example": "curl http://localhost:5001/api/network/dashboard/summary -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/network/subnets", - "auth": "permission:network.view", - "params": "not documented", - "purpose": "List all subnets with filtering and pagination.", - "example": "curl http://localhost:5001/api/network/subnets -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/network/subnets", - "auth": "permission:network.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new subnet.", - "example": "curl -X POST http://localhost:5001/api/network/subnets -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/network/subnets/", - "auth": "permission:network.delete", - "params": "path: subnet_id (int)", - "purpose": "Delete (soft delete) a subnet.", - "example": "curl -X DELETE http://localhost:5001/api/network/subnets/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/network/subnets/", - "auth": "permission:network.view", - "params": "path: subnet_id (int)", - "purpose": "Get a single subnet plus the network devices whose primary IP falls in its CIDR range.", - "example": "curl http://localhost:5001/api/network/subnets/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/network/subnets/", - "auth": "permission:network.edit", - "params": "path: subnet_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a subnet.", - "example": "curl -X PUT http://localhost:5001/api/network/subnets/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/network/types", - "auth": "permission:network.view", - "params": "not documented", - "purpose": "List all network device types.", - "example": "curl http://localhost:5001/api/network/types -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/network/types", - "auth": "permission:network.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new network device type.", - "example": "curl -X POST http://localhost:5001/api/network/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/network/types/", - "auth": "permission:network.delete", - "params": "path: type_id (int)", - "purpose": "Delete a network device type. Refused if any device still uses it.", - "example": "curl -X DELETE http://localhost:5001/api/network/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/network/types/", - "auth": "permission:network.view", - "params": "path: type_id (int)", - "purpose": "Get a single network device type.", - "example": "curl http://localhost:5001/api/network/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/network/types/", - "auth": "permission:network.edit", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a network device type.", - "example": "curl -X PUT http://localhost:5001/api/network/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/network/vlans", - "auth": "permission:network.view", - "params": "not documented", - "purpose": "List all VLANs with filtering and pagination.", - "example": "curl http://localhost:5001/api/network/vlans -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/network/vlans", - "auth": "permission:network.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new VLAN.", - "example": "curl -X POST http://localhost:5001/api/network/vlans -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/network/vlans/", - "auth": "permission:network.delete", - "params": "path: vlan_id (int)", - "purpose": "Delete (soft delete) a VLAN.", - "example": "curl -X DELETE http://localhost:5001/api/network/vlans/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/network/vlans/", - "auth": "permission:network.view", - "params": "path: vlan_id (int)", - "purpose": "Get a single VLAN with its subnets.", - "example": "curl http://localhost:5001/api/network/vlans/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/network/vlans/", - "auth": "permission:network.edit", - "params": "path: vlan_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a VLAN.", - "example": "curl -X PUT http://localhost:5001/api/network/vlans/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "requests": [ + { + "agentversion": "1.20.0", + "decidedat": null, + "decidedby": null, + "deviceid": null, + "hostname": "", + "lastseenat": "2026-01-01T00:00:00.000000Z", + "matchedassetid": 3, + "reason": "no serial on record", + "requestedat": "2026-01-01T00:00:00.000000Z", + "requestid": "00000000", + "serialnumber": "", + "sourceip": "127.0.0.1", + "status": "pending" + }, + { + "agentversion": "1.20.0", + "decidedat": null, + "decidedby": null, + "deviceid": null, + "hostname": "", + "lastseenat": "2026-01-01T00:00:00.000000Z", + "matchedassetid": 1, + "reason": null, + "requestedat": "2026-01-01T00:00:00.000000Z", + "requestid": "00000000", + "serialnumber": "", + "sourceip": "127.0.0.1", + "status": "issued" + } + ], + "settings": { + "autoenroll": true, + "maxpendingenrollments": 500, + "revokeddeniessharedkey": false, + "sharedkeyallowed": true } + }, + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 3, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/enrollment/assets//allow-reenroll", + "auth": "jwt + role:admin", + "params": "path: assetid (int); body: JSON (fields not yet documented)", + "purpose": "Lift a re-enrollment block. The PC enrolls on its next attempt.", + "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/assets/1/allow-reenroll -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "assetid": 1, + "credentialid": 1, + "credentialprefix": "", + "enrolledvia": "auto", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "reenrollblocked": false, + "reenrollblockedreason": null, + "revokedat": "2026-01-01T00:00:00.000000Z", + "revokedby": "testadmin" + }, + "message": "Re-enrollment allowed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/enrollment/assets//revoke", + "auth": "jwt + role:admin", + "params": "path: assetid (int); body: JSON (fields not yet documented)", + "purpose": "Un-enroll a PC. Its agent gets CREDENTIAL_INVALID and enrolls again.", + "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/assets/1/revoke -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "blockreenroll": true, + "reason": "rollback" + }, + "responseexample": { + "data": { + "assetid": 1, + "credentialid": 1, + "credentialprefix": "", + "enrolledvia": "auto", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "reenrollblocked": true, + "reenrollblockedreason": "rollback", + "revokedat": "2026-01-01T00:00:00.000000Z", + "revokedby": "testadmin" + }, + "message": "Endpoint credential revoked", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/enrollment/migration", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "Per-computer readiness to move onto per-PC credentials, plus waves.", + "example": "curl http://localhost:5001/api/endpoints/enrollment/migration -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "state", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "computers": [ + { + "agentversion": "1.19.0", + "assetid": 2, + "blockers": [], + "hostname": "", + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "state": "ready" + }, + { + "agentversion": "1.19.0", + "assetid": 3, + "blockers": [], + "hostname": "", + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "state": "ready" + }, + { + "agentversion": "1.20.0", + "assetid": 1, + "blockers": [ + "awaiting enrollment" + ], + "hostname": "", + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "state": "blocked" + } + ], + "counts": { + "blocked": 1, + "enrolled": 0, + "notreporting": 0, + "pending": 0, + "ready": 2, + "upgrading": 0 + }, + "target": "1.20.0", + "waves": [ + { + "createdat": "2026-01-01T00:00:00Z", + "createdby": "", + "done": false, + "enrolled": 0, + "failed": 1, + "queued": 3, + "size": 3, + "waveid": 1 + }, + { + "createdat": "2026-01-01T00:00:00Z", + "createdby": "", + "done": false, + "enrolled": 0, + "failed": 0, + "queued": 2, + "size": 2, + "waveid": 2 + } + ] + }, + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 3, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/enrollment/migration/wave", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Push the agent upgrade to a batch of READY PCs.", + "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/migration/wave -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "action": "run_script", + "target": "script:1" + }, + "responseexample": { + "data": { + "queued": [ + 1 + ], + "retried": [], + "skipped": [ + { + "assetid": 2, + "reason": "offline" + }, + { + "assetid": 3, + "reason": "notreporting" + }, + { + "assetid": 999999, + "reason": "not a computer" + } + ], + "waveid": 1 + }, + "message": "1 PC(s) queued", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/endpoints/enrollment/requests//approve", + "auth": "jwt + role:admin", + "params": "path: requestid (int); body: JSON (fields not yet documented)", + "purpose": "Bind a pending request to the asset the admin picked.", + "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/requests/1/approve -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "assetid": 1, + "sethostname": "" + }, + "responseexample": { + "data": { + "agentversion": "1.20.0", + "decidedat": "2026-01-01T00:00:00.000000Z", + "decidedby": "testadmin", + "deviceid": null, + "hostname": "", + "hostnameresult": "", + "lastseenat": "2026-01-01T00:00:00.000000Z", + "matchedassetid": 1, + "reason": null, + "requestedat": "2026-01-01T00:00:00.000000Z", + "requestid": "00000000", + "serialnumber": "", + "sourceip": "127.0.0.1", + "status": "approved" + }, + "message": "Enroll request approved; that computer was renamed to the hostname the PC reports", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/endpoints/enrollment/requests//reject", + "auth": "jwt + role:admin", + "params": "path: requestid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: endpoints.reject_enroll_request has no docstring.", + "example": "curl -X POST http://localhost:5001/api/endpoints/enrollment/requests/1/reject -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "agentversion": "1.20.0", + "decidedat": "2026-01-01T00:00:00.000000Z", + "decidedby": "testadmin", + "deviceid": null, + "hostname": "", + "lastseenat": "2026-01-01T00:00:00.000000Z", + "matchedassetid": 1, + "reason": "awaiting approval", + "requestedat": "2026-01-01T00:00:00.000000Z", + "requestid": "00000000", + "serialnumber": "", + "sourceip": "127.0.0.1", + "status": "rejected" + }, + "message": "Enroll request rejected", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/endpoints/enrollment/settings", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Change the enrollment settings.", + "example": "curl -X PUT http://localhost:5001/api/endpoints/enrollment/settings -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "revokeddeniessharedkey": true + }, + "responseexample": { + "data": { + "autoenroll": true, + "maxpendingenrollments": 500, + "revokeddeniessharedkey": false, + "sharedkeyallowed": false + }, + "message": "Enrollment settings saved", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/logcollections/", + "auth": "permission:endpoints.updateapp", + "params": "path: collection_id (int)", + "purpose": "One collected log including its content, for the scrollable pane.", + "example": "curl http://localhost:5001/api/endpoints/logcollections/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/logcollections//download", + "auth": "permission:endpoints.updateapp", + "params": "path: collection_id (int)", + "purpose": "Serve a collected log as a file attachment.", + "example": "curl http://localhost:5001/api/endpoints/logcollections/1/download -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/monitors", + "auth": "permission:endpoints.view", + "params": "not documented", + "purpose": "List monitor definitions (shipped and local).", + "example": "curl http://localhost:5001/api/endpoints/monitors -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/endpoints/monitors", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a user-defined (local) monitor definition.", + "example": "curl -X POST http://localhost:5001/api/endpoints/monitors -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/endpoints/monitors/", + "auth": "jwt + role:admin", + "params": "path: monitor_id (int)", + "purpose": "Delete a local monitor definition. Shipped rows are protected.", + "example": "curl -X DELETE http://localhost:5001/api/endpoints/monitors/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/endpoints/monitors/", + "auth": "jwt + role:admin", + "params": "path: monitor_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a local monitor definition. Shipped rows are read-only.", + "example": "curl -X PUT http://localhost:5001/api/endpoints/monitors/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "launchpath": "D:\\Dnc\\bin\\DncMain.exe" + }, + "responseexample": { + "data": { + "createdat": "2026-01-01T00:00:00.000000Z", + "datacollectorpath": null, + "displayname": "", + "endpointmonitorid": 1, + "isactive": false, + "kind": "process", + "launchpath": "C:\\Program Files\\Dnc\\bin\\DncMain.exe", + "logcollectorpath": null, + "processname": "UDC", + "servicename": null, + "source": "shipped" + }, + "message": "Monitor updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/monitors/resolve", + "auth": "permission:endpoints.view", + "params": "not documented", + "purpose": "Resolve the monitor set for a PC type (agent runtime fetch).", + "example": "curl http://localhost:5001/api/endpoints/monitors/resolve -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "pctype", + "type": "string", + "required": false + } ] - }, - { - "surface": "plugin-notifications", - "endpoints": [ - { - "method": "GET", - "path": "/api/notifications", - "auth": "permission:notifications.view", - "params": "not documented", - "purpose": "List all notifications with filtering and pagination.", - "example": "curl http://localhost:5001/api/notifications -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/monitors/resolved", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "not documented", + "purpose": "Agent watch list: the monitors this endpoint should report on.", + "example": "curl http://localhost:5001/api/endpoints/monitors/resolved -H \"X-API-Key: $KEY\"", + "queryparams": [ + { + "name": "hostname", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "processes": [ + { + "app": "Edge", + "launchpath": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", + "name": "msedge.exe" + } + ], + "services": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/operatorreports", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Agent uploads one operator issue report (collector-token auth).", + "example": "curl -X POST http://localhost:5001/api/endpoints/operatorreports -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "assetid": 1, + "createdat": "2026-01-01T00:00:00.000000Z", + "details": "the CMM app will not start", + "hasimage": true, + "imagebytesize": 70, + "imagemimetype": "image/png", + "operatorreportid": 1, + "reason": "Other (free text)", + "reportedhostname": "" + }, + "message": "Operator report received", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/operatorreports//image", + "auth": "permission:endpoints.operatorreports", + "params": "path: operatorreportid (int)", + "purpose": "Serve one operator report's screenshot.", + "example": "curl http://localhost:5001/api/endpoints/operatorreports/1/image -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/endpoints/panel//operatorreports", + "auth": "permission:endpoints.operatorreports", + "params": "path: asset_id (int)", + "purpose": "Operator Reports panel: this PC's recent operator issue reports.", + "example": "curl http://localhost:5001/api/endpoints/panel/1/operatorreports -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "reports": [ + { + "assetid": 1, + "createdat": "2026-01-01T00:00:00.000000Z", + "details": "second", + "hasimage": false, + "imagebytesize": null, + "imagemimetype": null, + "operatorreportid": 2, + "reason": "Other (free text)", + "reportedhostname": "" + }, + { + "assetid": 1, + "createdat": "2026-01-01T00:00:00.000000Z", + "details": "first", + "hasimage": false, + "imagebytesize": null, + "imagemimetype": null, + "operatorreportid": 1, + "reason": "Other (free text)", + "reportedhostname": "" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/scriptbody/", + "auth": "api-key (endpoint agent credential, or the fleet key while sharedkeyallowed is on)", + "params": "path: script_id (int)", + "purpose": "Agent-facing script body download (collector-token auth).", + "example": "curl http://localhost:5001/api/endpoints/scriptbody/1 -H \"X-API-Key: $KEY\"" + }, + { + "method": "GET", + "path": "/api/endpoints/settings/server-cert", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "Get details about the current server certificate.", + "example": "curl http://localhost:5001/api/endpoints/settings/server-cert -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "expires_in_days": 29, + "is_self_signed": true, + "issuer": "CN = pin.example.test", + "not_after": "Oct 18 18:57:47 2026 GMT", + "not_before": "Sep 17 18:57:47 2026 GMT", + "san_list": [], + "sha1thumbprint": "", + "spkisha256": "", + "subject_cn": "pin.example.test", + "thumbprint": "99:F1:E1:1D:5A:66:EE:44:8C:CA:5C:D8:BF:EA:C3:F3:8F:82:40:D3:5E:C9:4D:F0:AC:0B:3C:AD:80:D7:C1:DF" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/settings/server-cert/download", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "The PUBLIC server certificate as a DER .cer file, never the key.", + "example": "curl http://localhost:5001/api/endpoints/settings/server-cert/download -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/endpoints/settings/server-cert/generate", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Generate a new self-signed server certificate.", + "example": "curl -X POST http://localhost:5001/api/endpoints/settings/server-cert/generate -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "cn": "shopdb.example.test", + "days": 30, + "san": "" + }, + "responseexample": { + "data": { + "message": "Certificate generated successfully. Nginx is restarting." + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/settings/server-cert/live", + "auth": "permission:endpoints.fleet", + "params": "not documented", + "purpose": "The certificate PCs actually receive from this site's public address.", + "example": "curl http://localhost:5001/api/endpoints/settings/server-cert/live -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "configured": true, + "error": "Could not read the certificate from shopdb.example.test:443 (Connection refused)", + "matchesfile": false, + "presentedsha1thumbprint": null, + "presentedspkisha256": null, + "url": "https://shopdb.example.test" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/settings/server-cert/upload", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Upload a new server certificate and private key.", + "example": "curl -X POST http://localhost:5001/api/endpoints/settings/server-cert/upload -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "message": "Certificate uploaded successfully. Nginx is restarting." + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/siteagent", + "auth": "permission:endpoints.agentpackage", + "params": "not documented", + "purpose": "Report whether the site agent build has a prebuilt binary staged.", + "example": "curl http://localhost:5001/api/endpoints/siteagent -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "agentcurrent": null, + "agentlegacy": null, + "agentstaged": false, + "agentversions": [], + "certavailable": true, + "serverpin": "", + "sharedkeyallowed": false, + "traycurrent": null, + "traylegacy": null, + "traystaged": false, + "trayversions": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/endpoints/siteagent/binaries/", + "auth": "permission:endpoints.agentpackage", + "params": "path: binkey (string)", + "purpose": "List staged versions for a binary (agent or tray), newest first.", + "example": "curl http://localhost:5001/api/endpoints/siteagent/binaries/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/endpoints/siteagent/binaries/", + "auth": "permission:endpoints.agentpackage", + "params": "path: binkey (string); body: JSON (fields not yet documented)", + "purpose": "Stage an uploaded binary as a new version.", + "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/binaries/x -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "binary": "agent", + "current": "", + "registration": { + "agentversion": "", + "appid": 1, + "appname": "ShopDB Endpoint Agent", + "contents": { + "agent": { + "filename": "shopdbagent.exe", + "sha256": "", + "version": "" + } + }, + "created": false, + "installpath": "/api/applications/package/1/shopdb-endpoint-agent.zip", + "ok": true, + "sha256": "", + "size": 135 }, - { - "method": "POST", - "path": "/api/notifications", - "auth": "permission:notifications.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new notification.", - "example": "curl -X POST http://localhost:5001/api/notifications -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "versions": [ + { + "iscurrent": true, + "size": 130, + "uploadedat": "2026-01-01T00:00:00.000000Z", + "version": "" + }, + { + "iscurrent": false, + "size": 130, + "uploadedat": "2026-01-01T00:00:00.000000Z", + "version": "" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/endpoints/siteagent/binaries//adopt", + "auth": "permission:endpoints.agentpackage", + "params": "path: binkey (string); body: JSON (fields not yet documented)", + "purpose": "Adopt the unmanaged legacy flat file into the version store.", + "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/binaries/x/adopt -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "PUT", + "path": "/api/endpoints/siteagent/binaries//current", + "auth": "permission:endpoints.agentpackage", + "params": "path: binkey (string); body: JSON (fields not yet documented)", + "purpose": "Point 'current' at an already-staged version (roll back or forward).", + "example": "curl -X PUT http://localhost:5001/api/endpoints/siteagent/binaries/x/current -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "version": "" + }, + "responseexample": { + "data": { + "binary": "agent", + "current": "", + "registration": { + "agentversion": "", + "appid": 1, + "appname": "ShopDB Endpoint Agent", + "contents": { + "agent": { + "filename": "shopdbagent.exe", + "sha256": "", + "version": "" + } + }, + "created": false, + "installpath": "/api/applications/package/1/shopdb-endpoint-agent.zip", + "ok": true, + "sha256": "", + "size": 135 }, - { - "method": "DELETE", - "path": "/api/notifications/", - "auth": "permission:notifications.delete", - "params": "path: notification_id (int)", - "purpose": "Delete (soft delete) a notification.", - "example": "curl -X DELETE http://localhost:5001/api/notifications/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/notifications/", - "auth": "permission:notifications.view", - "params": "path: notification_id (int)", - "purpose": "Get a single notification.", - "example": "curl http://localhost:5001/api/notifications/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/notifications/", - "auth": "permission:notifications.edit", - "params": "path: notification_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a notification.", - "example": "curl -X PUT http://localhost:5001/api/notifications/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/notifications/active", - "auth": "permission:notifications.view", - "params": "not documented", - "purpose": "Get currently active notifications for display.", - "example": "curl http://localhost:5001/api/notifications/active -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/notifications/calendar", - "auth": "permission:notifications.view", - "params": "not documented", - "purpose": "Get notifications in FullCalendar event format.", - "example": "curl http://localhost:5001/api/notifications/calendar -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/notifications/dashboard/active", - "auth": "permission:notifications.view", - "params": "not documented", - "purpose": "Notifications currently showing on the floor.", - "example": "curl http://localhost:5001/api/notifications/dashboard/active -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/notifications/dashboard/summary", - "auth": "permission:notifications.view", - "params": "not documented", - "purpose": "Get notifications dashboard summary.", - "example": "curl http://localhost:5001/api/notifications/dashboard/summary -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/notifications/employee/", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "path: sso (string)", - "purpose": "Get recognitions for a specific employee by SSO.", - "example": "curl http://localhost:5001/api/notifications/employee/x" - }, - { - "method": "GET", - "path": "/api/notifications/shopfloor", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "Get notifications for shopfloor TV dashboard.", - "example": "curl http://localhost:5001/api/notifications/shopfloor" - }, - { - "method": "GET", - "path": "/api/notifications/types", - "auth": "permission:notifications.view", - "params": "not documented", - "purpose": "List all notification types.", - "example": "curl http://localhost:5001/api/notifications/types -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/notifications/types", - "auth": "permission:notifications.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new notification type.", - "example": "curl -X POST http://localhost:5001/api/notifications/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "PATCH|PUT", - "path": "/api/notifications/types/", - "auth": "permission:notifications.create", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a notification type, including its auto-expiry rule.", - "example": "curl -X PATCH http://localhost:5001/api/notifications/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "versions": [ + { + "iscurrent": false, + "size": 258, + "uploadedat": "2026-01-01T00:00:00.000000Z", + "version": "" + }, + { + "iscurrent": true, + "size": 258, + "uploadedat": "2026-01-01T00:00:00.000000Z", + "version": "" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/endpoints/siteagent/binaries//detect", + "auth": "permission:endpoints.agentpackage", + "params": "path: binkey (string); body: JSON (fields not yet documented)", + "purpose": "Read the PE file version of an uploaded EXE without staging it.", + "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/binaries/x/detect -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/endpoints/siteagent/bootstrap.ps1", + "auth": "api-key (single-use bootstrap token in the X-Endpoint-Bootstrap-Token header, or ?t= while that is enabled; per-IP rate limited, 404 when not usable)", + "params": "not documented", + "purpose": "The PowerShell the one-line command downloads, runs and deletes.", + "example": "curl http://localhost:5001/api/endpoints/siteagent/bootstrap.ps1" + }, + { + "method": "GET", + "path": "/api/endpoints/siteagent/bootstrap/package", + "auth": "api-key (single-use bootstrap token in the X-Endpoint-Bootstrap-Token header, or ?t= while that is enabled; per-IP rate limited, 404 when not usable)", + "params": "not documented", + "purpose": "The keyless agent package the bootstrap script installs.", + "example": "curl http://localhost:5001/api/endpoints/siteagent/bootstrap/package" + }, + { + "method": "GET", + "path": "/api/endpoints/siteagent/bootstrap/tokens", + "auth": "jwt + role:admin", + "params": "not documented", + "purpose": "Every bootstrap token, newest first. Never a secret.", + "example": "curl http://localhost:5001/api/endpoints/siteagent/bootstrap/tokens -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "tokens": [ + { + "createdat": "2026-01-01T00:00:00.000000Z", + "createdby": "", + "expiresat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "lastusedip": null, + "maxuses": 25, + "remaining": 25, + "revokedat": null, + "state": "active", + "tokenid": 1, + "tokenprefix": "", + "usecount": 0 + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/siteagent/bootstrap/tokens", + "auth": "jwt + role:admin", + "params": "body: JSON (fields not yet documented)", + "purpose": "Mint one short-lived bootstrap token. The secret is returned ONCE.", + "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/bootstrap/tokens -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "hours": 6, + "maxuses": 3 + }, + "responseexample": { + "data": { + "command": "powershell -ExecutionPolicy Bypass -c \"try { New-Item -ItemType Directory -Force -Path 'C:\\Program Files\\ShopDB\\bootstrap' | Out-Null; icacls 'C:\\Program Files\\ShopDB\\bootstrap' /inheritance:r /grant ...", + "scripturl": "https://shopdb.test/shopdb/api/endpoints/siteagent/bootstrap.ps1?t=&via=download", + "secret": "", + "token": { + "createdat": "2026-01-01T00:00:00.000000Z", + "createdby": "", + "expiresat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "lastusedip": null, + "maxuses": 500, + "remaining": 500, + "revokedat": null, + "state": "active", + "tokenid": 1, + "tokenprefix": "", + "usecount": 0 } - ] - }, - { - "surface": "plugin-printedparts", - "endpoints": [ - { - "method": "DELETE", - "path": "/api/printedparts/files/", - "auth": "permission:printedparts.delete", - "params": "path: file_id (int)", - "purpose": "Remove a bad revision (wrong file uploaded). History otherwise stays.", - "example": "curl -X DELETE http://localhost:5001/api/printedparts/files/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printedparts/files//download", - "auth": "permission:printedparts.view", - "params": "path: file_id (int)", - "purpose": "Download a revision under its original filename.", - "example": "curl http://localhost:5001/api/printedparts/files/1/download -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printedparts/image/", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "path: filename (path)", - "purpose": "Serve an uploaded item image (public - kiosk and list read it).", - "example": "curl http://localhost:5001/api/printedparts/image/example.png" - }, - { - "method": "GET", - "path": "/api/printedparts/items", - "auth": "permission:printedparts.view", - "params": "not documented", - "purpose": "List printed items, paginated; search + low-stock filter.", - "example": "curl http://localhost:5001/api/printedparts/items -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printedparts/items", - "auth": "permission:printedparts.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a printed item.", - "example": "curl -X POST http://localhost:5001/api/printedparts/items -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/printedparts/items/", - "auth": "permission:printedparts.delete", - "params": "path: item_id (int)", - "purpose": "Soft-retire an item; its ledger history stays.", - "example": "curl -X DELETE http://localhost:5001/api/printedparts/items/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printedparts/items/", - "auth": "permission:printedparts.view", - "params": "path: item_id (int)", - "purpose": "Get one printed item with its recent transactions.", - "example": "curl http://localhost:5001/api/printedparts/items/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/printedparts/items/", - "auth": "permission:printedparts.edit", - "params": "path: item_id (int); body: JSON (fields not yet documented)", - "purpose": "Update catalog fields. Quantity moves ONLY through the ledger.", - "example": "curl -X PUT http://localhost:5001/api/printedparts/items/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/printedparts/items//adjust", - "auth": "permission:printedparts.restock", - "params": "path: item_id (int); body: JSON (fields not yet documented)", - "purpose": "Correct the count (damage, recount). Body: {quantitychange, reason, badge}.", - "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/adjust -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printedparts/items//files", - "auth": "permission:printedparts.view", - "params": "path: item_id (int)", - "purpose": "Revision history, newest first.", - "example": "curl http://localhost:5001/api/printedparts/items/1/files -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printedparts/items//files", - "auth": "permission:printedparts.edit", - "params": "path: item_id (int); body: JSON (fields not yet documented)", - "purpose": "Upload the next revision of the item's print file.", - "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/files -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/printedparts/items//image", - "auth": "permission:printedparts.delete", - "params": "path: item_id (int)", - "purpose": "Clear an item image; delete the file only if this plugin owns it.", - "example": "curl -X DELETE http://localhost:5001/api/printedparts/items/1/image -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printedparts/items//image", - "auth": "permission:printedparts.edit", - "params": "path: item_id (int); body: JSON (fields not yet documented)", - "purpose": "Upload (or replace) the photo for an item (multipart file=).", - "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/image -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/printedparts/items//restock", - "auth": "permission:printedparts.restock", - "params": "path: item_id (int); body: JSON (fields not yet documented)", - "purpose": "Add freshly printed stock. Body: {quantity, badge}.", - "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/restock -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/printedparts/items//restore", - "auth": "permission:printedparts.delete", - "params": "path: item_id (int); body: JSON (fields not yet documented)", - "purpose": "Bring a retired item back; code, photo, and history are intact.", - "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/restore -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printedparts/kiosk/item/", - "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", - "params": "path: itemcode (string)", - "purpose": "Item summary for a scanned bin barcode. Kiosk-token gated.", - "example": "curl http://localhost:5001/api/printedparts/kiosk/item/x" - }, - { - "method": "GET", - "path": "/api/printedparts/kiosk/provisioning-link", - "auth": "permission:settings.edit", - "params": "not documented", - "purpose": "The URL that provisions a screen, token included, for an administrator.", - "example": "curl http://localhost:5001/api/printedparts/kiosk/provisioning-link -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printedparts/kiosk/take", - "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Take parts from a bin. Body: {itemcode, badge, quantity}.", - "example": "curl -X POST http://localhost:5001/api/printedparts/kiosk/take -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printedparts/reports/by-person", - "auth": "permission:printedparts.view", - "params": "not documented", - "purpose": "Takes grouped by employee, optionally bounded by ?days= (default 30).", - "example": "curl http://localhost:5001/api/printedparts/reports/by-person -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printedparts/reports/consumption", - "auth": "permission:printedparts.view", - "params": "not documented", - "purpose": "Takes per item, optionally bounded by ?days= (default 30).", - "example": "curl http://localhost:5001/api/printedparts/reports/consumption -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printedparts/reports/stock", - "auth": "permission:printedparts.view", - "params": "not documented", - "purpose": "Stock levels with low-stock flags and the cache-vs-ledger reconcile.", - "example": "curl http://localhost:5001/api/printedparts/reports/stock -H \"Authorization: Bearer $TOK\"" + }, + "message": "Bootstrap token created. The command is shown once.", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/endpoints/siteagent/bootstrap/tokens//revoke", + "auth": "jwt + role:admin", + "params": "path: tokenid (int); body: JSON (fields not yet documented)", + "purpose": "Kill a bootstrap token now. Already-revoked is a no-op, not an error.", + "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/bootstrap/tokens/1/revoke -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "token": { + "createdat": "2026-01-01T00:00:00.000000Z", + "createdby": "", + "expiresat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "lastusedip": null, + "maxuses": 25, + "remaining": 25, + "revokedat": "2026-01-01T00:00:00.000000Z", + "state": "revoked", + "tokenid": 1, + "tokenprefix": "", + "usecount": 0 } - ] - }, - { - "surface": "plugin-printers", - "endpoints": [ + }, + "message": "Bootstrap token revoked", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/endpoints/siteagent/package", + "auth": "permission:endpoints.agentpackage", + "params": "body: JSON (fields not yet documented)", + "purpose": "Bundle the site agent as a downloadable ZIP.", + "example": "curl -X POST http://localhost:5001/api/endpoints/siteagent/package -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "baseurl": "https://shopdb.test", + "bundlecert": true, + "cadenceseconds": 900, + "collectorkey": "", + "nextserverpin": "" + }, + "readsbody": true + } + ] + }, + { + "surface": "plugin-geenforce", + "endpoints": [ + { + "method": "GET", + "path": "/api/geenforce/applications", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "not documented", + "purpose": "The core Applications catalog (id + name) for the curated entry->app link picker in the entry editor.", + "example": "curl http://localhost:5001/api/geenforce/applications -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/printers", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "List all printers with filtering and pagination.", - "example": "curl http://localhost:5001/api/printers -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printers", - "auth": "permission:printers.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create new printer (creates both Asset and Printer records).", - "example": "curl -X POST http://localhost:5001/api/printers -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/printers/", - "auth": "permission:printers.delete", - "params": "path: printer_id (int)", - "purpose": "Delete (soft delete) printer.", - "example": "curl -X DELETE http://localhost:5001/api/printers/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/", - "auth": "permission:printers.view", - "params": "path: printer_id (int)", - "purpose": "Get a single printer with full details.", - "example": "curl http://localhost:5001/api/printers/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/printers/", - "auth": "permission:printers.edit", - "params": "path: printer_id (int); body: JSON (fields not yet documented)", - "purpose": "Update printer (both Asset and Printer records).", - "example": "curl -X PUT http://localhost:5001/api/printers/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printers//supplies", - "auth": "permission:printers.view", - "params": "path: printer_id (int)", - "purpose": "Get supply levels from Zabbix (real-time lookup).", - "example": "curl http://localhost:5001/api/printers/1/supplies -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/assignments/for-asset/", - "auth": "permission:printers.view", - "params": "path: asset_id (int)", - "purpose": "What THIS asset is assigned, without inheritance.", - "example": "curl http://localhost:5001/api/printers/assignments/for-asset/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/printers/assignments/for-asset/", - "auth": "permission:printers.edit", - "params": "path: asset_id (int); body: JSON (fields not yet documented)", - "purpose": "Reconcile one asset's whole printer assignment in a single call.", - "example": "curl -X PUT http://localhost:5001/api/printers/assignments/for-asset/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/printers/assignments/seed-from-observed/", - "auth": "permission:printers.edit", - "params": "path: asset_id (int); body: JSON (fields not yet documented)", - "purpose": "Write what a PC observed as the assignment of the asset in the path.", - "example": "curl -X POST http://localhost:5001/api/printers/assignments/seed-from-observed/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printers/by-asset/", - "auth": "permission:printers.view", - "params": "path: asset_id (int)", - "purpose": "Get printer data by asset ID.", - "example": "curl http://localhost:5001/api/printers/by-asset/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/dashboard/summary", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "Get printer dashboard summary data.", - "example": "curl http://localhost:5001/api/printers/dashboard/summary -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/dashboard/supplies", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "Printers needing a cartridge, flattened to one row per printer.", - "example": "curl http://localhost:5001/api/printers/dashboard/supplies -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/drivers", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "List printer drivers. ?active=false includes inactive ones.", - "example": "curl http://localhost:5001/api/printers/drivers -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printers/drivers", - "auth": "permission:printers.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: printers_asset.create_driver has no docstring.", - "example": "curl -X POST http://localhost:5001/api/printers/drivers -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/printers/drivers/", - "auth": "permission:printers.delete", - "params": "path: driver_id (int)", - "purpose": "UNDOCUMENTED: printers_asset.delete_driver has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/printers/drivers/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/printers/drivers/", - "auth": "permission:printers.edit", - "params": "path: driver_id (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: printers_asset.update_driver has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/printers/drivers/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printers/for-host/", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "path: hostname (string)", - "purpose": "Printers assigned to a PC, by hostname, with what it takes to install one.", - "example": "curl http://localhost:5001/api/printers/for-host/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/install-batch", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "Generate a Windows .bat that installs the selected printers.", - "example": "curl http://localhost:5001/api/printers/install-batch -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/install-list", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "Flat, unpaginated list of network printers for the printer installer.", - "example": "curl http://localhost:5001/api/printers/install-list -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/lookup", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "Find a printer by IP or FQDN. Parity with the classic printerlookup.asp.", - "example": "curl http://localhost:5001/api/printers/lookup -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/lowsupplies", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "Get printers with low or critical supply levels.", - "example": "curl http://localhost:5001/api/printers/lowsupplies -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/models", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "List models with a supply count, for the supply-management picker.", - "example": "curl http://localhost:5001/api/printers/models -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/models//supplies", - "auth": "permission:printers.view", - "params": "path: modelnumberid (int)", - "purpose": "List all supplies mapped to a model.", - "example": "curl http://localhost:5001/api/printers/models/1/supplies -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printers/models//supplies", - "auth": "permission:printers.create", - "params": "path: modelnumberid (int); body: JSON (fields not yet documented)", - "purpose": "Add a supply to a model.", - "example": "curl -X POST http://localhost:5001/api/printers/models/1/supplies -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printers/observed/", - "auth": "permission:printers.view", - "params": "path: hostname (string)", - "purpose": "What a host last reported, each queue judged against what it is assigned.", - "example": "curl http://localhost:5001/api/printers/observed/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/observed/for-asset/", - "auth": "permission:printers.view", - "params": "path: asset_id (int)", - "purpose": "The same comparison, reached from an asset page: one block per host.", - "example": "curl http://localhost:5001/api/printers/observed/for-asset/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/pc-default", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "not documented", - "purpose": "Default printer for a PC, by machine (asset) number.", - "example": "curl http://localhost:5001/api/printers/pc-default -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "DELETE", - "path": "/api/printers/supplies/", - "auth": "permission:printers.delete", - "params": "path: modelsupplyid (int)", - "purpose": "Delete a model supply.", - "example": "curl -X DELETE http://localhost:5001/api/printers/supplies/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/printers/supplies/", - "auth": "permission:printers.edit", - "params": "path: modelsupplyid (int); body: JSON (fields not yet documented)", - "purpose": "Update a model supply.", - "example": "curl -X PUT http://localhost:5001/api/printers/supplies/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printers/supplies/forecast", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "Days-to-empty and replacement counts per printer.", - "example": "curl http://localhost:5001/api/printers/supplies/forecast -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/supplies/meta", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "Allowed values for supply type, color, and capacity tier (for the UI).", - "example": "curl http://localhost:5001/api/printers/supplies/meta -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printers/supplies/refresh", - "auth": "permission:printers.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Clear cached Zabbix supply data so the next read pulls fresh values.", - "example": "curl -X POST http://localhost:5001/api/printers/supplies/refresh -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/printers/types", - "auth": "permission:printers.view", - "params": "not documented", - "purpose": "List all printer types.", - "example": "curl http://localhost:5001/api/printers/types -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/printers/types", - "auth": "permission:printers.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Create a new printer type.", - "example": "curl -X POST http://localhost:5001/api/printers/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/printers/types/", - "auth": "permission:printers.delete", - "params": "path: type_id (int)", - "purpose": "Delete a printer type. Refused if any printer still uses it.", - "example": "curl -X DELETE http://localhost:5001/api/printers/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/printers/types/", - "auth": "permission:printers.view", - "params": "path: type_id (int)", - "purpose": "Get a single printer type.", - "example": "curl http://localhost:5001/api/printers/types/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/printers/types/", - "auth": "permission:printers.edit", - "params": "path: type_id (int); body: JSON (fields not yet documented)", - "purpose": "Update a printer type.", - "example": "curl -X PUT http://localhost:5001/api/printers/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "appid": 1, + "appname": "eDNC (tracked)" } - ] - }, - { - "surface": "plugin-slides", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/geenforce/config", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "not documented", + "purpose": "Plugin config: the on-share export root + the client IP allowlist.", + "example": "curl http://localhost:5001/api/geenforce/config -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "allowedcidrs": "", + "shareroot": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/geenforce/config", + "auth": "permission:geenforce.publish", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: geenforce.put_config has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/geenforce/config -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "shareroot": "" + }, + "responseexample": { + "data": { + "shareroot": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/geenforce/dashboard/failures", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "not documented", + "purpose": "Entries that FAILED on their PC's most recent enforcement cycle.", + "example": "curl http://localhost:5001/api/geenforce/dashboard/failures -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/slides/", - "auth": "permission:slides.view or slides.manage", - "params": "path: surface (string)", - "purpose": "UNDOCUMENTED: slides.list_slides has no docstring.", - "example": "curl http://localhost:5001/api/slides/x -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PATCH", - "path": "/api/slides//", - "auth": "permission:slides.manage", - "params": "path: surface (string), slideid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: slides.update_slide has no docstring.", - "example": "curl -X PATCH http://localhost:5001/api/slides/x/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/slides//delete", - "auth": "permission:slides.manage", - "params": "path: surface (string); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: slides.delete_slides has no docstring.", - "example": "curl -X POST http://localhost:5001/api/slides/x/delete -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/slides//order", - "auth": "permission:slides.manage", - "params": "path: surface (string); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: slides.reorder_slides has no docstring.", - "example": "curl -X POST http://localhost:5001/api/slides/x/order -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/slides//upload", - "auth": "permission:slides.manage", - "params": "path: surface (string); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: slides.upload_slides has no docstring.", - "example": "curl -X POST http://localhost:5001/api/slides/x/upload -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/slides/feed", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "not documented", - "purpose": "Flat playlist for a surface. NOT wrapped in the success_response envelope so the screensaver's existing parser needs no change.", - "example": "curl http://localhost:5001/api/slides/feed" - }, - { - "method": "GET", - "path": "/api/slides/img//", - "auth": "none (reviewed: named in the public-read or mutation sweep)", - "params": "path: surface (string), filename (path)", - "purpose": "Serve a slide image with a path-traversal guard.", - "example": "curl http://localhost:5001/api/slides/img/x/example.png" + "computerid": null, + "entryname": "Install OpenText", + "exitcode": 1603, + "hostname": "", + "message": "Fatal error during installation", + "receivedat": "2026-01-01T00:00:00Z", + "scopename": "gea-shopfloor-cmm" } - ] - }, - { - "surface": "plugin-tools", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "DELETE", + "path": "/api/geenforce/entries/", + "auth": "permission:geenforce.manage", + "params": "path: entryid (int)", + "purpose": "UNDOCUMENTED: geenforce.delete_entry has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/geenforce/entries/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "deleted": 2 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/geenforce/entries/", + "auth": "permission:geenforce.manage", + "params": "path: entryid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: geenforce.update_entry has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/geenforce/entries/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "InUseCheck": { + "Behavior": "CloseAndReopen", + "Processes": [ + { + "ExePath": "C:\\PCDLRN.exe", + "GracefulCloseTimeoutSec": 15, + "Name": "PCDLRN" + } + ] + }, + "Installer": "apps/pcdmis.msi", + "LogFile": "C:\\Logs\\pcdmis.log", + "Name": "PC-DMIS", + "PCTypesStrict": true, + "PreEnrollment": true, + "Type": "MSI" + }, + "responseexample": { + "data": { + "InUseCheck": { + "Behavior": "CloseAndReopen", + "Processes": [ + { + "ExePath": "C:\\PCDLRN.exe", + "GracefulCloseTimeoutSec": 15, + "Name": "PCDLRN" + } + ] + }, + "Installer": "apps/pcdmis.msi", + "LogFile": "C:\\Logs\\pcdmis.log", + "Name": "PC-DMIS", + "PCTypesStrict": true, + "PreEnrollment": true, + "Type": "MSI", + "appid": null, + "appname": null, + "entryid": 1, + "haspayload": false, + "payloadref": null, + "payloadsha256": null, + "payloadsource": "smb", + "sortorder": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/geenforce/entries//payload", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: entryid (int)", + "purpose": "Return the stored inline payload bytes for an entry (404 if none).", + "example": "curl http://localhost:5001/api/geenforce/entries/1/payload -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/geenforce/entries//payload", + "auth": "permission:geenforce.publish", + "params": "path: entryid (int); body: JSON (fields not yet documented)", + "purpose": "Store an inline payload (<= 1 MB) for an entry and point the entry at it.", + "example": "curl -X POST http://localhost:5001/api/geenforce/entries/1/payload -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "Name": "eDNC install", + "PayloadRef": "config.reg", + "PayloadSha256": "", + "PayloadSource": "inline", + "Script": "scripts/x.ps1", + "Type": "PS1", + "appid": null, + "appname": null, + "entryid": 1, + "haspayload": true, + "payloadref": "config.reg", + "payloadsha256": "", + "payloadsource": "inline", + "sortorder": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/geenforce/manifest", + "auth": "api-key (geenforce fetch token, or the IP allowlist)", + "params": "not documented", + "purpose": "Serve the current published manifest for a scope (fat-client: full scope).", + "example": "curl http://localhost:5001/api/geenforce/manifest -H \"X-API-Key: $KEY\"", + "queryparams": [ + { + "name": "pctype", + "type": "string", + "required": false + }, + { + "name": "phase", + "type": "string", + "required": false + } + ], + "responseexample": { + "Version": "2.6", + "Applications": [ { - "method": "POST", - "path": "/api/tools/secrets", - "auth": "jwt-optional (works signed out; the handler decides what shows)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Store an already-encrypted secret and return its token.", - "example": "curl -X POST http://localhost:5001/api/tools/secrets -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "Name": "Alpha", + "Type": "MSI", + "Installer": "apps/alpha.msi", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\Alpha" }, { - "method": "GET", - "path": "/api/tools/secrets/", - "auth": "none (the unguessable token in the path is the authorisation)", - "params": "path: token (string)", - "purpose": "Whether a link is still live, WITHOUT spending it.", - "example": "curl http://localhost:5001/api/tools/secrets/x" + "Name": "Beta", + "Type": "PS1", + "Script": "scripts/beta.ps1", + "DetectionMethod": "Always" }, { - "method": "POST", - "path": "/api/tools/secrets/", - "auth": "none (the unguessable token in the path is the authorisation; redeeming spends the secret)", - "params": "path: token (string); body: JSON (fields not yet documented)", - "purpose": "Hand over the ciphertext once, then spend the view.", - "example": "curl -X POST http://localhost:5001/api/tools/secrets/x -H 'Content-Type: application/json' -d '{}'" + "Name": "Gamma", + "Type": "PS1", + "Script": "scripts/gamma.ps1" } - ] - }, - { - "surface": "plugin-usb", - "endpoints": [ + ] + } + }, + { + "method": "GET", + "path": "/api/geenforce/payload/", + "auth": "api-key (geenforce fetch token, or the IP allowlist)", + "params": "path: sha256 (string)", + "purpose": "Serve a payload blob by content hash over HTTPS.", + "example": "curl http://localhost:5001/api/geenforce/payload/x -H \"X-API-Key: $KEY\"" + }, + { + "method": "POST", + "path": "/api/geenforce/report", + "auth": "api-key (geenforce report token)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Record one PC's enforcement cycle: applied version (did it receive the update?) + per-entry self-heal outcomes (installed/skipped/failed).", + "example": "curl -X POST http://localhost:5001/api/geenforce/report -H \"X-API-Key: $KEY\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "appliedversion": 1, + "counts": { + "failed": 1, + "filtered": 0, + "installed": 2, + "skipped": 1 + }, + "enforcerversion": "2.6", + "hostname": "", + "phase": "runtime", + "results": [ { - "method": "GET", - "path": "/api/usb", - "auth": "permission:usb.view", - "params": "not documented", - "purpose": "List USB devices with checkout status.", - "example": "curl http://localhost:5001/api/usb -H \"Authorization: Bearer $TOK\"" + "action": "installed", + "exitcode": 0, + "message": "rule re-added", + "name": "VNC firewall rule", + "selfhealed": true }, { - "method": "POST", - "path": "/api/usb", - "auth": "permission:usb.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "Add a device (starts checked-in).", - "example": "curl -X POST http://localhost:5001/api/usb -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "action": "skipped", + "exitcode": 0, + "message": "", + "name": "PC-DMIS 2023.1", + "selfhealed": false }, { - "method": "GET", - "path": "/api/usb/", - "auth": "permission:usb.view", - "params": "path: device_id (string)", - "purpose": "Get a single device plus its last 20 check-in/out log rows.", - "example": "curl http://localhost:5001/api/usb/x -H \"Authorization: Bearer $TOK\"" + "action": "installed", + "exitcode": 0, + "name": "eDNC config", + "selfhealed": true }, + "" + ], + "scopename": "gea-shopfloor-cmm" + }, + "responseexample": { + "data": { + "reportid": 1, + "status": "selfhealed" + }, + "message": "recorded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/geenforce/reports", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "not documented", + "purpose": "Latest enforcement report per PC (fleet compliance view).", + "example": "curl http://localhost:5001/api/geenforce/reports -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "hostname", + "type": "string", + "required": false + }, + { + "name": "scopename", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ { - "method": "PUT", - "path": "/api/usb/", - "auth": "permission:usb.edit", - "params": "path: device_id (string); body: JSON (fields not yet documented)", - "purpose": "Edit device_desc / device_owner / locker_location / status.", - "example": "curl -X PUT http://localhost:5001/api/usb/x -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/usb//checkin", - "auth": "permission:usb.create", - "params": "path: device_id (string); body: JSON (fields not yet documented)", - "purpose": "Check a device back in from a badge.", - "example": "curl -X POST http://localhost:5001/api/usb/x/checkin -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/usb//checkout", - "auth": "permission:usb.create", - "params": "path: device_id (string); body: JSON (fields not yet documented)", - "purpose": "Check a device out to a badge.", - "example": "curl -X POST http://localhost:5001/api/usb/x/checkout -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/usb//history", - "auth": "permission:usb.view", - "params": "path: device_id (string)", - "purpose": "Paginated check-in/out log for one device.", - "example": "curl http://localhost:5001/api/usb/x/history -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/usb//retire", - "auth": "permission:usb.edit", - "params": "path: device_id (string); body: JSON (fields not yet documented)", - "purpose": "Retire a device (status -> retired).", - "example": "curl -X POST http://localhost:5001/api/usb/x/retire -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/usb/checkouts", - "auth": "permission:usb.view", - "params": "not documented", - "purpose": "List check-out log rows.", - "example": "curl http://localhost:5001/api/usb/checkouts -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/usb/checkouts/active", - "auth": "permission:usb.view", - "params": "not documented", - "purpose": "List the latest check-out log row for every currently checked-out device.", - "example": "curl http://localhost:5001/api/usb/checkouts/active -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/usb/kiosk/checkin", - "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Check a device in at the kiosk. Body: {device_id, badge, forsomeoneelse}.", - "example": "curl -X POST http://localhost:5001/api/usb/kiosk/checkin -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/usb/kiosk/checkout", - "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Check a device out at the kiosk. Body: {device_id, badge}.", - "example": "curl -X POST http://localhost:5001/api/usb/kiosk/checkout -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/usb/kiosk/device/", - "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", - "params": "path: device_id (string)", - "purpose": "What the kiosk shows after a device is scanned.", - "example": "curl http://localhost:5001/api/usb/kiosk/device/x" - }, - { - "method": "POST", - "path": "/api/usb/kiosk/others", - "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", - "params": "body: JSON (fields not yet documented)", - "purpose": "Drives checked out to OTHER people, with holder names. Body: {badge}.", - "example": "curl -X POST http://localhost:5001/api/usb/kiosk/others -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/usb/kiosk/provisioning-link", - "auth": "permission:settings.edit", - "params": "not documented", - "purpose": "The URL that provisions a screen, token included, for an administrator.", - "example": "curl http://localhost:5001/api/usb/kiosk/provisioning-link -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/usb/kiosk/session", - "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", - "params": "body: JSON (fields not yet documented)", - "purpose": "What one badge may do right now. Body: {badge}.", - "example": "curl -X POST http://localhost:5001/api/usb/kiosk/session -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/usb/kiosk/setup", - "auth": "setup-code (single-use kiosk setup code in ?code=, issued by the permission-gated provisioning link; spent on any attempt, 410 once used or expired)", - "params": "not documented", - "purpose": "Trade a setup code for this browser's kiosk cookie, then open the kiosk.", - "example": "curl http://localhost:5001/api/usb/kiosk/setup" - }, - { - "method": "GET", - "path": "/api/usb/reports/audit", - "auth": "permission:usb.view", - "params": "not documented", - "purpose": "Every check-out and check-in in the window, newest first.", - "example": "curl http://localhost:5001/api/usb/reports/audit -H \"Authorization: Bearer $TOK\"" + "appliedversion": null, + "assetnumber": "WJBAK10", + "backupcollectedat": "2026-01-01T00:00:00.000000Z", + "backupkind": "partmarker", + "backuplastseen": "2026-01-01T00:00:00.000000Z", + "backupok": false, + "backupstaleafterdays": 3, + "computerid": 1, + "displayrole": null, + "enforcerversion": null, + "failed": 0, + "filtered": 0, + "hostname": "", + "installed": 0, + "isstale": false, + "lastcheckin": null, + "latestversion": 1, + "levelid": null, + "location": null, + "machineassetid": null, + "machinenumber": null, + "machinepluginid": null, + "mapx": null, + "mapy": null, + "phase": "runtime", + "receivedat": "2026-01-01T00:00:00.000000Z", + "receivedlatest": false, + "reportid": 1, + "scopename": "gea-shopfloor-cmm", + "skipped": 0, + "staleafterminutes": 30, + "status": "ok", + "toolassetid": null, + "toolassetnumber": null, + "toolpluginid": null } - ] - }, - { - "surface": "plugin-warranty", - "endpoints": [ + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/geenforce/reports/", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: reportid (int)", + "purpose": "One report with per-entry outcomes (self-heal / failure detail).", + "example": "curl http://localhost:5001/api/geenforce/reports/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "appliedversion": 1, + "hostname": "", + "latestversion": 1, + "phase": "runtime", + "receivedlatest": true, + "reportid": 1, + "results": [ + { + "action": "installed", + "entryname": "VNC firewall rule", + "exitcode": 0, + "message": "rule re-added", + "selfhealed": true + }, + { + "action": "skipped", + "entryname": "PC-DMIS 2023.1", + "exitcode": 0, + "message": "", + "selfhealed": false + }, + { + "action": "installed", + "entryname": "eDNC config", + "exitcode": 0, + "message": null, + "selfhealed": true + }, + "" + ], + "scopename": "gea-shopfloor-cmm", + "status": "failed" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/geenforce/scopes", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "not documented", + "purpose": "List imaging PC-type scopes with entry + published-version counts.", + "example": "curl http://localhost:5001/api/geenforce/scopes -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ { - "method": "GET", - "path": "/api/warranty", - "auth": "permission:warranty.view", - "params": "not documented", - "purpose": "List warranties. Filters: ?status=, ?assetid=, ?active=false.", - "example": "curl http://localhost:5001/api/warranty -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/warranty", - "auth": "permission:warranty.create", - "params": "body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: warranty.create_warranty has no docstring.", - "example": "curl -X POST http://localhost:5001/api/warranty -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/warranty/", - "auth": "permission:warranty.delete", - "params": "path: warrantyid (int)", - "purpose": "UNDOCUMENTED: warranty.delete_warranty has no docstring.", - "example": "curl -X DELETE http://localhost:5001/api/warranty/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/warranty/", - "auth": "permission:warranty.view", - "params": "path: warrantyid (int)", - "purpose": "UNDOCUMENTED: warranty.get_warranty has no docstring.", - "example": "curl http://localhost:5001/api/warranty/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "PUT", - "path": "/api/warranty/", - "auth": "permission:warranty.edit", - "params": "path: warrantyid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: warranty.update_warranty has no docstring.", - "example": "curl -X PUT http://localhost:5001/api/warranty/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "DELETE", - "path": "/api/warranty//proof", - "auth": "permission:warranty.edit", - "params": "path: warrantyid (int)", - "purpose": "Remove a warranty's proof document.", - "example": "curl -X DELETE http://localhost:5001/api/warranty/1/proof -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/warranty//proof", - "auth": "permission:warranty.edit", - "params": "path: warrantyid (int); body: JSON (fields not yet documented)", - "purpose": "Upload (or replace) the proof-of-cover document for a warranty.", - "example": "curl -X POST http://localhost:5001/api/warranty/1/proof -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "POST", - "path": "/api/warranty//refresh", - "auth": "permission:warranty.edit", - "params": "path: warrantyid (int); body: JSON (fields not yet documented)", - "purpose": "UNDOCUMENTED: warranty.refresh_warranty has no docstring.", - "example": "curl -X POST http://localhost:5001/api/warranty/1/refresh -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" - }, - { - "method": "GET", - "path": "/api/warranty/asset/", - "auth": "permission:warranty.view", - "params": "path: assetid (int)", - "purpose": "Warranties covering one asset (for the asset-detail panel).", - "example": "curl http://localhost:5001/api/warranty/asset/1 -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/warranty/dashboard/expiring", - "auth": "permission:warranty.view", - "params": "not documented", - "purpose": "Warranties running out, and ones that already have.", - "example": "curl http://localhost:5001/api/warranty/dashboard/expiring -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/warranty/proof/", - "auth": "permission:warranty.view", - "params": "path: filename (path)", - "purpose": "Download a proof document.", - "example": "curl http://localhost:5001/api/warranty/proof/example.png -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "GET", - "path": "/api/warranty/report", - "auth": "permission:warranty.view", - "params": "not documented", - "purpose": "Counts + lists bucketed by derived status.", - "example": "curl http://localhost:5001/api/warranty/report -H \"Authorization: Bearer $TOK\"" - }, - { - "method": "POST", - "path": "/api/warranty/sync/dell", - "auth": "permission:warranty.edit", - "params": "body: JSON (fields not yet documented)", - "purpose": "Look up every asset serial (= Dell service tag) that has no warranty yet and create warranties for the ones Dell recognizes.", - "example": "curl -X POST http://localhost:5001/api/warranty/sync/dell -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + "computertypeid": null, + "entrycount": 2, + "iscommon": false, + "manifestversion": "2.6", + "measuringtooltypeid": null, + "minlibversion": null, + "phase": "runtime", + "publishedversion": 1, + "scopeid": 1, + "scopename": "gea-shopfloor-cmm" } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/geenforce/scopes", + "auth": "permission:geenforce.manage", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: geenforce.create_scope has no docstring.", + "example": "curl -X POST http://localhost:5001/api/geenforce/scopes -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "description": "test scope", + "phase": "runtime", + "scopename": "gea-shopfloor-collections" + }, + "responseexample": { + "data": { + "computertypeid": null, + "description": "test scope", + "entrycount": 0, + "iscommon": false, + "manifestversion": "1.0", + "measuringtooltypeid": null, + "phase": "runtime", + "publishedversion": null, + "scopeid": 1, + "scopename": "gea-shopfloor-collections" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/geenforce/scopes/", + "auth": "permission:geenforce.manage", + "params": "path: scopeid (int)", + "purpose": "UNDOCUMENTED: geenforce.delete_scope has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/geenforce/scopes/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "deleted": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/geenforce/scopes/", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: scopeid (int)", + "purpose": "UNDOCUMENTED: geenforce.get_scope has no docstring.", + "example": "curl http://localhost:5001/api/geenforce/scopes/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "computertypeid": null, + "description": "test scope", + "entries": [ + { + "Name": "Beta", + "Script": "scripts/b.ps1", + "Type": "PS1", + "appid": null, + "appname": null, + "entryid": 2, + "haspayload": false, + "payloadref": null, + "payloadsha256": null, + "payloadsource": "smb", + "sortorder": 0 + }, + { + "DetectionMethod": "FileVersion", + "DetectionPath": "C:\\a.exe", + "DetectionValue": "1.0", + "Installer": "apps/a.exe", + "Name": "Alpha", + "Type": "EXE", + "appid": null, + "appname": null, + "entryid": 1, + "haspayload": false, + "payloadref": null, + "payloadsha256": null, + "payloadsource": "smb", + "sortorder": 1 + } + ], + "entrycount": 2, + "iscommon": false, + "manifestversion": "1.0", + "measuringtooltypeid": null, + "phase": "runtime", + "publishedversion": null, + "scopeid": 1, + "scopename": "gea-shopfloor-test" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/geenforce/scopes/", + "auth": "permission:geenforce.manage", + "params": "path: scopeid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: geenforce.update_scope has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/geenforce/scopes/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "computertypeid": 3, + "description": "updated" + }, + "responseexample": { + "data": { + "computertypeid": 3, + "description": "updated", + "entrycount": 0, + "iscommon": false, + "manifestversion": "1.0", + "measuringtooltypeid": null, + "phase": "runtime", + "publishedversion": null, + "scopeid": 1, + "scopename": "gea-shopfloor-test" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/geenforce/scopes//compliance", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: scopeid (int)", + "purpose": "Fleet-install coverage per app-linked entry (from collected PC data).", + "example": "curl http://localhost:5001/api/geenforce/scopes/1/compliance -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "computersplugin": false, + "phase": "runtime", + "rows": [ + { + "appid": 1, + "appname": "PC-DMIS", + "coveragenote": "computers plugin not installed; install counts unavailable", + "entryid": 1, + "entryname": "PC-DMIS 2019", + "expectedversion": "2019 R1", + "installedcount": null, + "versionmatchcount": null + } + ], + "scopeid": 1, + "scopename": "gea-shopfloor-cmm" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/geenforce/scopes//entries", + "auth": "permission:geenforce.manage", + "params": "path: scopeid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: geenforce.create_entry has no docstring.", + "example": "curl -X POST http://localhost:5001/api/geenforce/scopes/1/entries -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "InUseCheck": { + "Behavior": "CloseAndReopen", + "Processes": [ + { + "ExePath": "C:\\PCDLRN.exe", + "GracefulCloseTimeoutSec": 15, + "Name": "PCDLRN" + } + ] + }, + "Installer": "apps/pcdmis.msi", + "LogFile": "C:\\Logs\\pcdmis.log", + "Name": "PC-DMIS", + "PCTypesStrict": true, + "PreEnrollment": true, + "Type": "MSI" + }, + "responseexample": { + "data": { + "InUseCheck": { + "Behavior": "CloseAndReopen", + "Processes": [ + { + "ExePath": "C:\\PCDLRN.exe", + "GracefulCloseTimeoutSec": 15, + "Name": "PCDLRN" + } + ] + }, + "Installer": "apps/pcdmis.msi", + "LogFile": "C:\\Logs\\pcdmis.log", + "Name": "PC-DMIS", + "PCTypesStrict": true, + "PreEnrollment": true, + "Type": "MSI", + "appid": null, + "appname": null, + "entryid": 1, + "haspayload": false, + "payloadref": null, + "payloadsha256": null, + "payloadsource": "smb", + "sortorder": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "PUT", + "path": "/api/geenforce/scopes//entries/reorder", + "auth": "permission:geenforce.manage", + "params": "path: scopeid (int); body: JSON (fields not yet documented)", + "purpose": "Set entry order from a list of entryids (the ordering contract).", + "example": "curl -X PUT http://localhost:5001/api/geenforce/scopes/1/entries/reorder -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "order": [ + 2, + 1 + ] + }, + "responseexample": { + "data": { + "order": [ + 2, + 1 + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/geenforce/scopes//export-share", + "auth": "permission:geenforce.publish", + "params": "path: scopeid (int); body: JSON (fields not yet documented)", + "purpose": "Write the scope's current published JSON to the configured share root (backing up the old file to _meta/history first).", + "example": "curl -X POST http://localhost:5001/api/geenforce/scopes/1/export-share -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "path": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/geenforce/scopes//preview", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: scopeid (int)", + "purpose": "Render the DRAFT manifest JSON a publish would freeze (review before ship).", + "example": "curl http://localhost:5001/api/geenforce/scopes/1/preview -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "manifest": { + "Applications": [ + { + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\Alpha", + "Installer": "apps/alpha.msi", + "Name": "Alpha", + "Type": "MSI" + }, + { + "DetectionMethod": "Always", + "Name": "Beta", + "Script": "scripts/beta.ps1", + "Type": "PS1" + } + ], + "Version": "2.6" + }, + "scopename": "gea-shopfloor-cmm" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/geenforce/scopes//publish", + "auth": "permission:geenforce.publish", + "params": "path: scopeid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: geenforce.publish_scope_route has no docstring.", + "example": "curl -X POST http://localhost:5001/api/geenforce/scopes/1/publish -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "notes": "v1" + }, + "responseexample": { + "data": { + "versionnumber": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/geenforce/scopes//publish-preflight", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: scopeid (int)", + "purpose": "Would publishing this scope outrun the fleet's enforcer lib?", + "example": "curl http://localhost:5001/api/geenforce/scopes/1/publish-preflight -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/geenforce/scopes//rollback", + "auth": "permission:geenforce.publish", + "params": "path: scopeid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: geenforce.rollback_scope_route has no docstring.", + "example": "curl -X POST http://localhost:5001/api/geenforce/scopes/1/rollback -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "versionnumber": 1 + }, + "responseexample": { + "data": { + "versionnumber": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/geenforce/scopes//simulate", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: scopeid (int)", + "purpose": "Which draft entries apply to a given machine profile, and why the rest are filtered out (reuses the engine-mirror filters).", + "example": "curl http://localhost:5001/api/geenforce/scopes/1/simulate -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "cmmversion", + "type": "string", + "required": false + }, + { + "name": "hostname", + "type": "string", + "required": false + }, + { + "name": "machinenumber", + "type": "string", + "required": false + }, + { + "name": "pctype", + "type": "string", + "required": false + }, + { + "name": "subtype", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "applied": [ + "CLM (untagged)", + "PC-DMIS 2019" + ], + "filtered": [ + { + "filteredby": [ + "_CmmVersion" + ], + "name": "PC-DMIS 2016" + } + ], + "profile": { + "cmmversion": "2019", + "hostname": "", + "machinenumber": null, + "pctype": "gea-shopfloor-cmm", + "phase": "runtime", + "subtype": null + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/geenforce/scopes//versions", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: scopeid (int)", + "purpose": "UNDOCUMENTED: geenforce.list_versions has no docstring.", + "example": "curl http://localhost:5001/api/geenforce/scopes/1/versions -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ + { + "iscurrent": false, + "notes": "v2", + "publishedat": "2026-01-01T00:00:00.000000Z", + "publishedby": 1, + "versionnumber": 2 + }, + { + "iscurrent": true, + "notes": "v1", + "publishedat": "2026-01-01T00:00:00.000000Z", + "publishedby": 1, + "versionnumber": 1 + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/geenforce/scopes//versions/", + "auth": "permission:geenforce.view or geenforce.manage", + "params": "path: scopeid (int), versionnumber (int)", + "purpose": "UNDOCUMENTED: geenforce.get_version has no docstring.", + "example": "curl http://localhost:5001/api/geenforce/scopes/1/versions/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "manifest": { + "Applications": [ + { + "Name": "Alpha", + "Type": "MSI" + }, + { + "Name": "Beta", + "Type": "PS1" + } + ], + "Version": "1.0" + }, + "versionnumber": 2 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "plugin-guides", + "endpoints": [ + { + "method": "GET", + "path": "/api/guides", + "auth": "permission:guides.view", + "params": "not documented", + "purpose": "Published guides, plus the caller's own drafts if they can author.", + "example": "curl http://localhost:5001/api/guides -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "q", + "type": "string", + "required": false + }, + { + "name": "tag", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ + { + "canedit": false, + "checklistitems": 0, + "createdat": "2026-01-01T00:00:00.000000Z", + "guideid": 1, + "ispublished": true, + "publishedat": "2026-01-01T00:00:00.000000Z", + "revision": 2, + "slug": "published-procedure", + "status": "published", + "summary": null, + "tags": [], + "title": "Published procedure", + "updatedat": "2026-01-01T00:00:00.000000Z" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/guides", + "auth": "permission:guides.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: guides.create_guide has no docstring.", + "example": "curl -X POST http://localhost:5001/api/guides -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "blocks": [], + "title": "Replacing a marker controler" + }, + "responseexample": { + "data": { + "blocks": [], + "createdat": "2026-01-01T00:00:00.000000Z", + "guideid": 1, + "publishedat": null, + "revision": 1, + "slug": "replacing-a-marker-controler", + "status": "draft", + "summary": null, + "tags": [], + "title": "Replacing a marker controler", + "updatedat": "2026-01-01T00:00:00.000000Z" + }, + "message": "Guide created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/guides/", + "auth": "permission:guides.delete", + "params": "path: guideid (int)", + "purpose": "UNDOCUMENTED: guides.delete_guide has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/guides/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/guides/", + "auth": "permission:guides.view", + "params": "path: guideid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: guides.update_guide has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/guides/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "blocks": [], + "title": "Replacing a marker controller" + }, + "responseexample": { + "data": { + "blocks": [], + "createdat": "2026-01-01T00:00:00.000000Z", + "guideid": 1, + "publishedat": null, + "revision": 2, + "saved": true, + "slug": "replacing-a-marker-controler", + "status": "draft", + "summary": null, + "tags": [], + "title": "Replacing a marker controller", + "updatedat": "2026-01-01T00:00:00.000000Z" + }, + "message": "Saved", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/guides//publish", + "auth": "permission:guides.publish", + "params": "path: guideid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: guides.publish_guide has no docstring.", + "example": "curl -X POST http://localhost:5001/api/guides/1/publish -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "POST", + "path": "/api/guides//restore/", + "auth": "permission:guides.view", + "params": "path: guideid (int), revisionid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: guides.restore_revision has no docstring.", + "example": "curl -X POST http://localhost:5001/api/guides/1/restore/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "GET", + "path": "/api/guides//revisions", + "auth": "permission:guides.view", + "params": "path: guideid (int)", + "purpose": "UNDOCUMENTED: guides.list_revisions has no docstring.", + "example": "curl http://localhost:5001/api/guides/1/revisions -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/guides//unpublish", + "auth": "permission:guides.publish", + "params": "path: guideid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: guides.unpublish_guide has no docstring.", + "example": "curl -X POST http://localhost:5001/api/guides/1/unpublish -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "GET", + "path": "/api/guides//working", + "auth": "permission:guides.view", + "params": "path: guideid (int)", + "purpose": "The working copy, for the editor.", + "example": "curl http://localhost:5001/api/guides/1/working -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/guides/", + "auth": "permission:guides.view", + "params": "path: slug (string)", + "purpose": "What a reader gets: the published revision.", + "example": "curl http://localhost:5001/api/guides/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/guides/images", + "auth": "permission:guides.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Take a pasted or dropped image.", + "example": "curl -X POST http://localhost:5001/api/guides/images -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "bytesize": 40, + "createdat": "2026-01-01T00:00:00.000000Z", + "filename": "screenshot.png", + "guideid": null, + "guideimageid": 1, + "mimetype": "image/png", + "url": "/api/guides/images/1" + }, + "message": "Image uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/guides/images/", + "auth": "permission:guides.view", + "params": "path: imageid (int)", + "purpose": "The image itself, under the same rule as the guide that holds it.", + "example": "curl http://localhost:5001/api/guides/images/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/guides/revisions/", + "auth": "permission:guides.view", + "params": "path: revisionid (int)", + "purpose": "One revision by id.", + "example": "curl http://localhost:5001/api/guides/revisions/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "blocks": [ + { + "id": "b1", + "text": "secret draft wording", + "type": "paragraph" + } + ], + "createdat": "2026-01-01T00:00:00.000000Z", + "createdby": "", + "guideid": 1, + "guiderevisionid": 1, + "note": null, + "revision": 1, + "shorthash": "", + "summary": null, + "tags": [], + "title": "Published procedure" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/guides/tags", + "auth": "permission:guides.view", + "params": "not documented", + "purpose": "Every tag in use, with a count, for the filter chips.", + "example": "curl http://localhost:5001/api/guides/tags -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "plugin-knowledgebase", + "endpoints": [ + { + "method": "GET", + "path": "/api/knowledgebase", + "auth": "permission:kb.view", + "params": "not documented", + "purpose": "List all knowledge base articles.", + "example": "curl http://localhost:5001/api/knowledgebase -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "appid", + "type": "integer", + "required": false + }, + { + "name": "linkurl", + "type": "string", + "required": false + }, + { + "name": "order", + "type": "string", + "required": false, + "default": "desc" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "shortdescription", + "type": "string", + "required": false + }, + { + "name": "sort", + "type": "string", + "required": false, + "default": "clicks" + } + ], + "responseexample": { + "data": [ + { + "appid": 1, + "application": { + "appid": 1, + "appname": "Spotfire" + }, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "install", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 3, + "linkurl": "https://kb.example/c", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "Spotfire install guide" + }, + { + "appid": 1, + "application": { + "appid": 1, + "appname": "Spotfire" + }, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "export", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 2, + "linkurl": "https://kb.example/b", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "Export a visualization" + }, + { + "appid": 1, + "application": { + "appid": 1, + "appname": "Spotfire" + }, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "login", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 1, + "linkurl": "https://kb.example/a", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "Dashboard login steps" + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 3, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/knowledgebase", + "auth": "permission:kb.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new knowledge base article.", + "example": "curl -X POST http://localhost:5001/api/knowledgebase -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "keywords": "printer reset", + "linkurl": "https://kb.example/printer-reset", + "shortdescription": "How to reset a printer" + }, + "responseexample": { + "data": { + "appid": null, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "printer reset", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 1, + "linkurl": "https://kb.example/printer-reset", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "How to reset a printer" + }, + "message": "Article created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/knowledgebase/", + "auth": "permission:kb.delete", + "params": "path: link_id (int)", + "purpose": "Delete (deactivate) a knowledge base article.", + "example": "curl -X DELETE http://localhost:5001/api/knowledgebase/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/knowledgebase/", + "auth": "permission:kb.view", + "params": "path: link_id (int)", + "purpose": "Get a single knowledge base article.", + "example": "curl http://localhost:5001/api/knowledgebase/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "appid": null, + "application": null, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "printer reset", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 1, + "linkurl": "https://kb.example/printer-reset", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "How to reset a printer" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/knowledgebase/", + "auth": "permission:kb.edit", + "params": "path: link_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a knowledge base article.", + "example": "curl -X PUT http://localhost:5001/api/knowledgebase/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/knowledgebase//click", + "auth": "permission:kb.view", + "params": "path: link_id (int); body: JSON (fields not yet documented)", + "purpose": "Increment the click counter for an article the caller is allowed to read.", + "example": "curl -X POST http://localhost:5001/api/knowledgebase/1/click -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "GET", + "path": "/api/knowledgebase/stats", + "auth": "permission:kb.view", + "params": "not documented", + "purpose": "Get knowledge base statistics.", + "example": "curl http://localhost:5001/api/knowledgebase/stats -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "totalarticles": 0, + "totalclicks": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "plugin-machines", + "endpoints": [ + { + "method": "GET", + "path": "/api/machines", + "auth": "permission:machines.view", + "params": "not documented", + "purpose": "List all machines with filtering and pagination.", + "example": "curl http://localhost:5001/api/machines -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "assetnumber", + "type": "string", + "required": false + }, + { + "name": "businessunit_id", + "type": "integer", + "required": false + }, + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "dir", + "type": "string", + "required": false, + "default": "asc" + }, + { + "name": "location_id", + "type": "integer", + "required": false + }, + { + "name": "locationid", + "type": "integer", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "sort", + "type": "string", + "required": false, + "default": "assetnumber" + }, + { + "name": "type_id", + "type": "integer", + "required": false + }, + { + "name": "typeid", + "type": "integer", + "required": false + }, + { + "name": "vendor_id", + "type": "integer", + "required": false + }, + { + "name": "vendorid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [ + { + "assetid": 1, + "assetnumber": "0410", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "machine", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "dualpathpartner": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "machine": { + "assetid": 1, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": null, + "machineid": 1, + "machinetypeid": 1, + "machinetypename": "Part Washer", + "maintenanceintervaldays": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": null, + "requiresmanualconfig": false, + "vendorid": 1, + "vendorname": "Acme Industrial" + }, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Cell 4 washer", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/machines", + "auth": "permission:machines.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create new machine (creates both Asset and Machine records).", + "example": "curl -X POST http://localhost:5001/api/machines -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "assetnumber": "MAINT-DATE-1", + "lastmaintenancedate": "2026-01-01", + "name": "Maintenance date probe", + "nextmaintenancedate": "2026-01-01" + }, + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "MAINT-DATE-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "machine", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "machine": { + "assetid": 1, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": "2026-01-01", + "machineid": 1, + "machinetypeid": null, + "maintenanceintervaldays": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": "2026-01-01", + "requiresmanualconfig": false, + "vendorid": null + }, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Maintenance date probe", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "message": "Machine created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/machines/", + "auth": "permission:machines.delete", + "params": "path: machine_id (int)", + "purpose": "Delete (soft delete) machine.", + "example": "curl -X DELETE http://localhost:5001/api/machines/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/machines/", + "auth": "permission:machines.view", + "params": "path: machine_id (int)", + "purpose": "Get a single machine item with full details.", + "example": "curl http://localhost:5001/api/machines/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "2001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "machine", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "dualpathpartner": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "machine": { + "assetid": 1, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "imageurl": "/api/models/images/model-1.png", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": null, + "machineid": 1, + "machinetypeid": null, + "maintenanceintervaldays": null, + "modelname": "IMG-MODEL-1", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": null, + "requiresmanualconfig": false, + "vendorid": null + }, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/machines/", + "auth": "permission:machines.edit", + "params": "path: machine_id (int); body: JSON (fields not yet documented)", + "purpose": "Update machine (both Asset and Machine records).", + "example": "curl -X PUT http://localhost:5001/api/machines/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/machines/by-asset/", + "auth": "permission:machines.view", + "params": "path: asset_id (int)", + "purpose": "Get machine data by asset ID.", + "example": "curl http://localhost:5001/api/machines/by-asset/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/machines/dashboard/outofservice", + "auth": "permission:machines.view", + "params": "not documented", + "purpose": "Machines whose status says they are not running.", + "example": "curl http://localhost:5001/api/machines/dashboard/outofservice -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/machines/dashboard/summary", + "auth": "permission:machines.view", + "params": "not documented", + "purpose": "Get machine dashboard summary data.", + "example": "curl http://localhost:5001/api/machines/dashboard/summary -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "bystatus": [ + { + "count": 1, + "status": "In Use" + } + ], + "bytype": [], + "total": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/machines/types", + "auth": "permission:machines.view", + "params": "not documented", + "purpose": "List all machine types.", + "example": "curl http://localhost:5001/api/machines/types -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/machines/types", + "auth": "permission:machines.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new machine type.", + "example": "curl -X POST http://localhost:5001/api/machines/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/machines/types/", + "auth": "permission:machines.delete", + "params": "path: type_id (int)", + "purpose": "Delete a machine type. Refused if any asset still uses it.", + "example": "curl -X DELETE http://localhost:5001/api/machines/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/machines/types/", + "auth": "permission:machines.view", + "params": "path: type_id (int)", + "purpose": "Get a single machine type.", + "example": "curl http://localhost:5001/api/machines/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/machines/types/", + "auth": "permission:machines.edit", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a machine type.", + "example": "curl -X PUT http://localhost:5001/api/machines/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "plugin-measuringtools", + "endpoints": [ + { + "method": "GET", + "path": "/api/measuringtools", + "auth": "permission:measuringtools.view", + "params": "not documented", + "purpose": "List measuring tools with filters + pagination.", + "example": "curl http://localhost:5001/api/measuringtools -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "assetnumber", + "type": "string", + "required": false + }, + { + "name": "calibrationstatus", + "type": "string", + "required": false + }, + { + "name": "locationid", + "type": "integer", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "statusid", + "type": "integer", + "required": false + }, + { + "name": "typeid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [ + { + "assetid": 26, + "assetnumber": "MT-PAGE-05", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "measuring_tool", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "measuringtool": { + "assetid": 26, + "calibrationintervaldays": null, + "calibrationprovider": null, + "calibrationstatus": "overdue", + "calibrationstatuscolor": "#F44336", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "lastcalibrationdate": null, + "measuringtoolid": 26, + "measuringtooltypeid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextcalibrationdate": "2026-01-01", + "notes": null + }, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Paged tool 5", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 26, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 2, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/measuringtools", + "auth": "permission:measuringtools.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a measuring tool: one Asset core row + one extension row.", + "example": "curl -X POST http://localhost:5001/api/measuringtools -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "assetnumber": "MT-001", + "calibrationintervaldays": 365, + "calibrationprovider": "Metro Cal Lab", + "gaugelabreference": "GL-42", + "lastcalibrationdate": "2026-01-01", + "measuringtooltypeid": 1, + "name": "Bench caliper", + "nextcalibrationdate": "2026-01-01", + "serialnumber": "", + "statusid": 1 + }, + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "MT-001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "measuring_tool", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-42", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "measuringtool": { + "assetid": 1, + "calibrationintervaldays": 365, + "calibrationprovider": "Metro Cal Lab", + "calibrationstatus": "current", + "calibrationstatuscolor": "#4CAF50", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "lastcalibrationdate": "2026-01-01", + "measuringtoolid": 1, + "measuringtooltypecolor": "#14abef", + "measuringtooltypeid": 1, + "measuringtooltypename": "Caliper", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextcalibrationdate": "2026-01-01", + "notes": null + }, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Bench caliper", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "message": "Measuring tool created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/measuringtools/", + "auth": "permission:measuringtools.delete", + "params": "path: tool_id (int)", + "purpose": "Soft delete a measuring tool (deactivates its asset).", + "example": "curl -X DELETE http://localhost:5001/api/measuringtools/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Measuring tool deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/measuringtools/", + "auth": "permission:measuringtools.view", + "params": "path: tool_id (int)", + "purpose": "Get one measuring tool (asset core merged with the extension).", + "example": "curl http://localhost:5001/api/measuringtools/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "MT-001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "measuring_tool", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-42", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "measuringtool": { + "assetid": 1, + "calibrationintervaldays": 365, + "calibrationprovider": "Metro Cal Lab", + "calibrationstatus": "current", + "calibrationstatuscolor": "#4CAF50", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "lastcalibrationdate": "2026-01-01", + "measuringtoolid": 1, + "measuringtooltypecolor": "#14abef", + "measuringtooltypeid": 1, + "measuringtooltypename": "Caliper", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextcalibrationdate": "2026-01-01", + "notes": null + }, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Bench caliper", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/measuringtools/", + "auth": "permission:measuringtools.edit", + "params": "path: tool_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a measuring tool (asset core fields + extension in one payload).", + "example": "curl -X PUT http://localhost:5001/api/measuringtools/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "calibrationprovider": "In-house", + "name": "Renamed tool", + "nextcalibrationdate": "2026-01-01" + }, + "responseexample": { + "data": { + "assetid": 20, + "assetnumber": "MT-AUDIT-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "measuring_tool", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "measuringtool": { + "assetid": 20, + "calibrationintervaldays": null, + "calibrationprovider": null, + "calibrationstatus": "current", + "calibrationstatuscolor": "#4CAF50", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "lastcalibrationdate": "2026-01-01", + "measuringtoolid": 20, + "measuringtooltypeid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextcalibrationdate": "2026-01-01", + "notes": null + }, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "After rename", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 20, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "message": "Measuring tool updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/measuringtools/by-asset/", + "auth": "permission:measuringtools.view", + "params": "path: asset_id (int)", + "purpose": "Get a measuring tool by its core asset id.", + "example": "curl http://localhost:5001/api/measuringtools/by-asset/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/measuringtools/map-overlay", + "auth": "permission:measuringtools.view", + "params": "not documented", + "purpose": "Calibration-status overlay for active measuring tools.", + "example": "curl http://localhost:5001/api/measuringtools/map-overlay -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ + { + "assetid": 4, + "color": "#F44336", + "label": "Overdue" + }, + { + "assetid": 6, + "color": "#F44336", + "label": "Overdue" + }, + { + "assetid": 16, + "color": "#F44336", + "label": "Overdue" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/measuringtools/report/calibration", + "auth": "permission:measuringtools.view", + "params": "not documented", + "purpose": "Counts + lists bucketed by derived calibration status.", + "example": "curl http://localhost:5001/api/measuringtools/report/calibration -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "buckets": { + "current": [], + "duesoon": [], + "overdue": [], + "unknown": [] + }, + "counts": { + "current": 0, + "duesoon": 0, + "overdue": 0, + "unknown": 0 + }, + "statuscolors": { + "current": "#4CAF50", + "duesoon": "#FF9800", + "overdue": "#F44336", + "unknown": "#9E9E9E" + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/measuringtools/types", + "auth": "permission:measuringtools.view", + "params": "not documented", + "purpose": "List measuring-tool types.", + "example": "curl http://localhost:5001/api/measuringtools/types -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ + { + "color": "#7934f3", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Bore / hole diameter gage", + "isactive": true, + "measuringtooltypeid": 4, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Bore Gage" + }, + { + "color": "#14abef", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Vernier / digital caliper", + "isactive": true, + "measuringtooltypeid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Caliper" + }, + { + "color": "#e83e8c", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Reference gage block set", + "isactive": true, + "measuringtooltypeid": 7, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Gage Block Set" + }, + "" + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 8, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/measuringtools/types", + "auth": "permission:measuringtools.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a measuring-tool type (reactivates a soft-deleted same-named one).", + "example": "curl -X POST http://localhost:5001/api/measuringtools/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "color": "#123456", + "description": "Pin gage set", + "name": "Pin Gage" + }, + "responseexample": { + "data": { + "color": "#123456", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Pin gage set", + "isactive": true, + "measuringtooltypeid": 9, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Pin Gage" + }, + "message": "Measuring-tool type created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/measuringtools/types/", + "auth": "permission:measuringtools.delete", + "params": "path: type_id (int)", + "purpose": "Delete a measuring-tool type. Refused if any tool still uses it.", + "example": "curl -X DELETE http://localhost:5001/api/measuringtools/types/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Measuring-tool type deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/measuringtools/types/", + "auth": "permission:measuringtools.view", + "params": "path: type_id (int)", + "purpose": "Get one measuring-tool type.", + "example": "curl http://localhost:5001/api/measuringtools/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/measuringtools/types/", + "auth": "permission:measuringtools.edit", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a measuring-tool type.", + "example": "curl -X PUT http://localhost:5001/api/measuringtools/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "description": "Updated" + }, + "responseexample": { + "data": { + "color": "#123456", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Updated", + "isactive": true, + "measuringtooltypeid": 9, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Pin Gage" + }, + "message": "Measuring-tool type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + } + ] + }, + { + "surface": "plugin-network", + "endpoints": [ + { + "method": "GET", + "path": "/api/network", + "auth": "permission:network.view", + "params": "not documented", + "purpose": "List all network devices with filtering and pagination.", + "example": "curl http://localhost:5001/api/network -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "assetnumber", + "type": "string", + "required": false + }, + { + "name": "businessunit_id", + "type": "integer", + "required": false + }, + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "dir", + "type": "string", + "required": false, + "default": "asc" + }, + { + "name": "location_id", + "type": "integer", + "required": false + }, + { + "name": "locationid", + "type": "integer", + "required": false + }, + { + "name": "managed", + "type": "string", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "poe", + "type": "string", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "sort", + "type": "string", + "required": false, + "default": "hostname" + }, + { + "name": "type_id", + "type": "integer", + "required": false + }, + { + "name": "typeid", + "type": "integer", + "required": false + }, + { + "name": "vendor_id", + "type": "integer", + "required": false + }, + { + "name": "vendorid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [ + { + "assetid": 1, + "assetnumber": "NET-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "network_device", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "networkdevice": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "firmwareversion": null, + "hostname": "", + "isactive": true, + "ismanaged": false, + "ispoe": false, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdeviceid": 1, + "networkdevicetypeid": 1, + "networkdevicetypename": "Switch", + "portcount": null, + "rackunit": null, + "vendorid": 1, + "vendorname": "Cisco" + }, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/network", + "auth": "permission:network.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create new network device (creates both Asset and NetworkDevice records).", + "example": "curl -X POST http://localhost:5001/api/network -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "assetnumber": "SW-CORE-01", + "hostname": "", + "ipaddress": "", + "name": "Core switch" + }, + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "APNL-Dock-Door-4", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "network_device", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Dock Door 4", + "networkdevice": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "firmwareversion": null, + "hostname": "", + "isactive": true, + "ismanaged": false, + "ispoe": false, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdeviceid": 1, + "networkdevicetypeid": 1, + "networkdevicetypename": "Access Panel", + "portcount": null, + "rackunit": null, + "vendorid": null + }, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "message": "Network device created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/network/", + "auth": "permission:network.delete", + "params": "path: device_id (int)", + "purpose": "Delete (soft delete) network device.", + "example": "curl -X DELETE http://localhost:5001/api/network/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/network/", + "auth": "permission:network.view", + "params": "path: device_id (int)", + "purpose": "Get a single network device with full details.", + "example": "curl http://localhost:5001/api/network/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "AST-networkdevice", + "assettypecolor": null, + "assettypeid": 3, + "assettypename": "network_device", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-2", + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": "MNT-2", + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "networkdevice": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "firmwareversion": null, + "hostname": "", + "isactive": true, + "ismanaged": false, + "ispoe": false, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdeviceid": 1, + "networkdevicetypeid": null, + "portcount": null, + "rackunit": null, + "vendorid": null + }, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/network/", + "auth": "permission:network.edit", + "params": "path: device_id (int); body: JSON (fields not yet documented)", + "purpose": "Update network device (both Asset and NetworkDevice records).", + "example": "curl -X PUT http://localhost:5001/api/network/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "gaugelabreference": "GL-2", + "maintenancereference": "MNT-2" + }, + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "AST-networkdevice", + "assettypecolor": null, + "assettypeid": 3, + "assettypename": "network_device", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-2", + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": "MNT-2", + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "networkdevice": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "firmwareversion": null, + "hostname": "", + "isactive": true, + "ismanaged": false, + "ispoe": false, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdeviceid": 1, + "networkdevicetypeid": null, + "portcount": null, + "rackunit": null, + "vendorid": null + }, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "message": "Network device updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/network/by-asset/", + "auth": "permission:network.view", + "params": "path: asset_id (int)", + "purpose": "Get network device data by asset ID.", + "example": "curl http://localhost:5001/api/network/by-asset/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/network/by-hostname/", + "auth": "permission:network.view", + "params": "path: hostname (string)", + "purpose": "Get network device by hostname.", + "example": "curl http://localhost:5001/api/network/by-hostname/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/network/dashboard/summary", + "auth": "permission:network.view", + "params": "not documented", + "purpose": "Get network device dashboard summary data.", + "example": "curl http://localhost:5001/api/network/dashboard/summary -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "bytype": [], + "byvendor": [], + "nonpoe": 0, + "poe": 0, + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/network/subnets", + "auth": "permission:network.view", + "params": "not documented", + "purpose": "List all subnets with filtering and pagination.", + "example": "curl http://localhost:5001/api/network/subnets -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "locationid", + "type": "integer", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "type", + "type": "string", + "required": false + }, + { + "name": "vlanid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/network/subnets", + "auth": "permission:network.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new subnet.", + "example": "curl -X POST http://localhost:5001/api/network/subnets -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "cidr": "", + "name": "Attached", + "vlanid": 1 + }, + "responseexample": { + "data": { + "broadcastaddress": null, + "cidr": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "dhcpenabled": true, + "dhcprangeend": null, + "dhcprangestart": null, + "dns1": null, + "dns2": null, + "gatewayip": null, + "isactive": true, + "locationid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Attached", + "networkaddress": null, + "subnetid": 1, + "subnetmask": null, + "subnettype": null, + "vlanid": 1, + "vlanname": "In use", + "vlannumber": 77 + }, + "message": "Subnet created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/network/subnets/", + "auth": "permission:network.delete", + "params": "path: subnet_id (int)", + "purpose": "Delete (soft delete) a subnet.", + "example": "curl -X DELETE http://localhost:5001/api/network/subnets/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/network/subnets/", + "auth": "permission:network.view", + "params": "path: subnet_id (int)", + "purpose": "Get a single subnet plus the network devices whose primary IP falls in its CIDR range.", + "example": "curl http://localhost:5001/api/network/subnets/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/network/subnets/", + "auth": "permission:network.edit", + "params": "path: subnet_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a subnet.", + "example": "curl -X PUT http://localhost:5001/api/network/subnets/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/network/types", + "auth": "permission:network.view", + "params": "not documented", + "purpose": "List all network device types.", + "example": "curl http://localhost:5001/api/network/types -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/network/types", + "auth": "permission:network.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new network device type.", + "example": "curl -X POST http://localhost:5001/api/network/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "networkdevicetype": "Door Controller", + "prefix": "DOOR" + }, + "responseexample": { + "data": { + "color": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "icon": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdevicetype": "Door Controller", + "networkdevicetypeid": 1, + "prefix": "DOOR" + }, + "message": "Network device type created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/network/types/", + "auth": "permission:network.delete", + "params": "path: type_id (int)", + "purpose": "Delete a network device type. Refused if any device still uses it.", + "example": "curl -X DELETE http://localhost:5001/api/network/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/network/types/", + "auth": "permission:network.view", + "params": "path: type_id (int)", + "purpose": "Get a single network device type.", + "example": "curl http://localhost:5001/api/network/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/network/types/", + "auth": "permission:network.edit", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a network device type.", + "example": "curl -X PUT http://localhost:5001/api/network/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "prefix": "DR" + }, + "responseexample": { + "data": { + "color": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "icon": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdevicetype": "Door Controller", + "networkdevicetypeid": 1, + "prefix": "DR" + }, + "message": "Network device type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/network/vlans", + "auth": "permission:network.view", + "params": "not documented", + "purpose": "List all VLANs with filtering and pagination.", + "example": "curl http://localhost:5001/api/network/vlans -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "type", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/network/vlans", + "auth": "permission:network.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new VLAN.", + "example": "curl -X POST http://localhost:5001/api/network/vlans -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "name": "VLAN 4094", + "vlannumber": 4094 + }, + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "VLAN 4094", + "subnetcount": 0, + "vlanid": 1, + "vlannumber": 4094, + "vlantype": null + }, + "message": "VLAN created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/network/vlans/", + "auth": "permission:network.delete", + "params": "path: vlan_id (int)", + "purpose": "Delete (soft delete) a VLAN.", + "example": "curl -X DELETE http://localhost:5001/api/network/vlans/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/network/vlans/", + "auth": "permission:network.view", + "params": "path: vlan_id (int)", + "purpose": "Get a single VLAN with its subnets.", + "example": "curl http://localhost:5001/api/network/vlans/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/network/vlans/", + "auth": "permission:network.edit", + "params": "path: vlan_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a VLAN.", + "example": "curl -X PUT http://localhost:5001/api/network/vlans/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "plugin-notifications", + "endpoints": [ + { + "method": "GET", + "path": "/api/notifications", + "auth": "permission:notifications.view", + "params": "not documented", + "purpose": "List all notifications with filtering and pagination.", + "example": "curl http://localhost:5001/api/notifications -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "current", + "type": "string", + "required": false, + "default": "false" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "ticketnumber", + "type": "string", + "required": false + }, + { + "name": "type_id", + "type": "integer", + "required": false + }, + { + "name": "typeid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/notifications", + "auth": "permission:notifications.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new notification.", + "example": "curl -X POST http://localhost:5001/api/notifications -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "alertfleet": true, + "alertscope": { + "computertype": "CMM PC", + "hostname": [ + "", + "" + ] + }, + "notification": "Line 3 is down", + "notificationtypeid": 1 + }, + "responseexample": { + "data": { + "alertfleet": true, + "alertscope": { + "computertype": "CMM PC", + "hostname": [ + "", + "" + ] + }, + "alerttimeout": 0, + "appid": null, + "businessunitid": null, + "employeename": "", + "employeesso": "", + "enddate": null, + "endtime": null, + "isactive": true, + "iscurrent": true, + "isshopfloor": false, + "link": null, + "linkurl": null, + "message": "Line 3 is down", + "notification": "Line 3 is down", + "notificationid": 1, + "notificationtypeid": 1, + "startdate": "2026-01-01T00:00:00.000000+00:00", + "starttime": "2026-01-01T00:00:00.000000+00:00", + "ticketnumber": null, + "title": "Line 3 is down", + "typecolor": "#d93f3f", + "typename": "Fleet Alert" + }, + "message": "Notification created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/notifications/", + "auth": "permission:notifications.delete", + "params": "path: notification_id (int)", + "purpose": "Delete (soft delete) a notification.", + "example": "curl -X DELETE http://localhost:5001/api/notifications/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/notifications/", + "auth": "permission:notifications.view", + "params": "path: notification_id (int)", + "purpose": "Get a single notification.", + "example": "curl http://localhost:5001/api/notifications/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/notifications/", + "auth": "permission:notifications.edit", + "params": "path: notification_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a notification.", + "example": "curl -X PUT http://localhost:5001/api/notifications/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "alertfleet": null, + "alerttimeout": null + }, + "responseexample": { + "data": { + "alertfleet": false, + "alertscope": null, + "alerttimeout": 0, + "appid": null, + "businessunitid": null, + "employeename": "", + "employeesso": "", + "enddate": null, + "endtime": null, + "isactive": true, + "iscurrent": true, + "isshopfloor": false, + "link": null, + "linkurl": null, + "message": "Line 3 is down", + "notification": "Line 3 is down", + "notificationid": 1, + "notificationtypeid": 1, + "startdate": "2026-01-01T00:00:00.000000+00:00", + "starttime": "2026-01-01T00:00:00.000000+00:00", + "ticketnumber": null, + "title": "Line 3 is down", + "typecolor": "#d93f3f", + "typename": "Fleet Alert" + }, + "message": "Notification updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/notifications/active", + "auth": "permission:notifications.view", + "params": "not documented", + "purpose": "Get currently active notifications for display.", + "example": "curl http://localhost:5001/api/notifications/active -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "notifications": [], + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/notifications/calendar", + "auth": "permission:notifications.view", + "params": "not documented", + "purpose": "Get notifications in FullCalendar event format.", + "example": "curl http://localhost:5001/api/notifications/calendar -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "end", + "type": "string", + "required": false + }, + { + "name": "start", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/notifications/dashboard/active", + "auth": "permission:notifications.view", + "params": "not documented", + "purpose": "Notifications currently showing on the floor.", + "example": "curl http://localhost:5001/api/notifications/dashboard/active -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/notifications/dashboard/summary", + "auth": "permission:notifications.view", + "params": "not documented", + "purpose": "Get notifications dashboard summary.", + "example": "curl http://localhost:5001/api/notifications/dashboard/summary -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "active": 0, + "bytype": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/notifications/employee/", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "path: sso (string)", + "purpose": "Get recognitions for a specific employee by SSO.", + "example": "curl http://localhost:5001/api/notifications/employee/x" + }, + { + "method": "GET", + "path": "/api/notifications/shopfloor", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "Get notifications for shopfloor TV dashboard.", + "example": "curl http://localhost:5001/api/notifications/shopfloor", + "queryparams": [ + { + "name": "businessunit", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "configversion": "2b7c2d2f543f", + "current": [ + { + "boardcategory": "Current Events", + "boardorder": 50, + "displaystyle": "grid", + "employeename": "", + "employeepicture": "", + "employeesso": "", + "endtime": null, + "isactive": true, + "isshopfloor": true, + "link": null, + "notification": "press down", + "notificationid": 2, + "resolved": false, + "starttime": null, + "ticketnumber": null, + "typecolor": "#17a2b8", + "typename": "Incident" + }, + { + "boardcategory": "Current Events", + "boardorder": 30, + "displaystyle": "grid", + "employeename": "", + "employeepicture": "", + "employeesso": "", + "endtime": null, + "isactive": true, + "isshopfloor": true, + "link": null, + "notification": "retooling", + "notificationid": 1, + "resolved": false, + "starttime": null, + "ticketnumber": null, + "typecolor": "#17a2b8", + "typename": "Change" + } + ], + "timestamp": "2026-01-01T00:00:00.000000", + "upcoming": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/notifications/types", + "auth": "permission:notifications.view", + "params": "not documented", + "purpose": "List all notification types.", + "example": "curl http://localhost:5001/api/notifications/types -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [ + { + "boardcategory": "Alerts", + "boardorder": 100, + "displaystyle": "grid", + "expirydays": null, + "expiryhour": null, + "expiryminute": 0, + "expirymode": "none", + "gracewindowminutes": 0, + "isactive": true, + "notificationtypeid": 1, + "showemployeephoto": "", + "splitperemployee": "", + "typecolor": "#17a2b8", + "typedescription": null, + "typename": "Awareness" + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/notifications/types", + "auth": "permission:notifications.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new notification type.", + "example": "curl -X POST http://localhost:5001/api/notifications/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "boardcategory": "Alerts", + "displaystyle": "grid", + "typename": "Awareness" + }, + "responseexample": { + "data": { + "boardcategory": "Alerts", + "boardorder": 100, + "displaystyle": "grid", + "expirydays": null, + "expiryhour": null, + "expiryminute": 0, + "expirymode": "none", + "gracewindowminutes": 0, + "isactive": true, + "notificationtypeid": 1, + "showemployeephoto": "", + "splitperemployee": "", + "typecolor": "#17a2b8", + "typedescription": null, + "typename": "Awareness" + }, + "message": "Notification type created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "PATCH|PUT", + "path": "/api/notifications/types/", + "auth": "permission:notifications.create", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a notification type, including its auto-expiry rule.", + "example": "curl -X PATCH http://localhost:5001/api/notifications/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "boardcategory": "Alerts" + }, + "responseexample": { + "data": { + "boardcategory": "Alerts", + "boardorder": 100, + "displaystyle": "grid", + "expirydays": null, + "expiryhour": null, + "expiryminute": 0, + "expirymode": "none", + "gracewindowminutes": 0, + "isactive": true, + "notificationtypeid": 1, + "showemployeephoto": "", + "splitperemployee": "", + "typecolor": "#17a2b8", + "typedescription": null, + "typename": "Awareness" + }, + "message": "Notification type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + } + ] + }, + { + "surface": "plugin-printedparts", + "endpoints": [ + { + "method": "DELETE", + "path": "/api/printedparts/files/", + "auth": "permission:printedparts.delete", + "params": "path: file_id (int)", + "purpose": "Remove a bad revision (wrong file uploaded). History otherwise stays.", + "example": "curl -X DELETE http://localhost:5001/api/printedparts/files/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/printedparts/files//download", + "auth": "permission:printedparts.view", + "params": "path: file_id (int)", + "purpose": "Download a revision under its original filename.", + "example": "curl http://localhost:5001/api/printedparts/files/1/download -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/printedparts/image/", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "path: filename (path)", + "purpose": "Serve an uploaded item image (public - kiosk and list read it).", + "example": "curl http://localhost:5001/api/printedparts/image/example.png" + }, + { + "method": "GET", + "path": "/api/printedparts/items", + "auth": "permission:printedparts.view", + "params": "not documented", + "purpose": "List printed items, paginated; search + low-stock filter.", + "example": "curl http://localhost:5001/api/printedparts/items -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "lowstock", + "type": "string", + "required": false, + "default": "" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ + { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": "WJRP0117", + "imageurl": null, + "isactive": true, + "islowstock": true, + "itemcode": "3DP0001", + "itemdescription": null, + "itemname": "Gage block holder", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 0 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/printedparts/items", + "auth": "permission:printedparts.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a printed item.", + "example": "curl -X POST http://localhost:5001/api/printedparts/items -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "gagelabtag": "wjrp0117", + "itemname": "Gage block holder" + }, + "responseexample": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": "WJRP0117", + "imageurl": null, + "isactive": true, + "islowstock": true, + "itemcode": "3DP0001", + "itemdescription": null, + "itemname": "Gage block holder", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 0 + }, + "message": "Printed item created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/printedparts/items/", + "auth": "permission:printedparts.delete", + "params": "path: item_id (int)", + "purpose": "Soft-retire an item; its ledger history stays.", + "example": "curl -X DELETE http://localhost:5001/api/printedparts/items/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Printed item retired", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printedparts/items/", + "auth": "permission:printedparts.view", + "params": "path: item_id (int)", + "purpose": "Get one printed item with its recent transactions.", + "example": "curl http://localhost:5001/api/printedparts/items/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/printedparts/items/", + "auth": "permission:printedparts.edit", + "params": "path: item_id (int); body: JSON (fields not yet documented)", + "purpose": "Update catalog fields. Quantity moves ONLY through the ledger.", + "example": "curl -X PUT http://localhost:5001/api/printedparts/items/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/printedparts/items//adjust", + "auth": "permission:printedparts.restock", + "params": "path: item_id (int); body: JSON (fields not yet documented)", + "purpose": "Correct the count (damage, recount). Body: {quantitychange, reason, badge}.", + "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/adjust -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/printedparts/items//files", + "auth": "permission:printedparts.view", + "params": "path: item_id (int)", + "purpose": "Revision history, newest first.", + "example": "curl http://localhost:5001/api/printedparts/items/1/files -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [ + { + "fileid": 2, + "filename": "clip_v2.gcode", + "filesize": 8, + "printeditemid": 1, + "revision": 2, + "uploadedby": "testadmin", + "uploadeddate": "2026-01-01T00:00:00.000000Z", + "uploadnote": null + }, + { + "fileid": 1, + "filename": "clip_v1.stl", + "filesize": 10, + "printeditemid": 1, + "revision": 1, + "uploadedby": "testadmin", + "uploadeddate": "2026-01-01T00:00:00.000000Z", + "uploadnote": "initial" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/printedparts/items//files", + "auth": "permission:printedparts.edit", + "params": "path: item_id (int); body: JSON (fields not yet documented)", + "purpose": "Upload the next revision of the item's print file.", + "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/files -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "fileid": 1, + "filename": "clip_v1.stl", + "filesize": 10, + "printeditemid": 1, + "revision": 1, + "uploadedby": "testadmin", + "uploadeddate": "2026-01-01T00:00:00.000000Z", + "uploadnote": "initial" + }, + "message": "Revision 1 uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/printedparts/items//image", + "auth": "permission:printedparts.delete", + "params": "path: item_id (int)", + "purpose": "Clear an item image; delete the file only if this plugin owns it.", + "example": "curl -X DELETE http://localhost:5001/api/printedparts/items/1/image -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/printedparts/items//image", + "auth": "permission:printedparts.edit", + "params": "path: item_id (int); body: JSON (fields not yet documented)", + "purpose": "Upload (or replace) the photo for an item (multipart file=).", + "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/image -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/printedparts/items//restock", + "auth": "permission:printedparts.restock", + "params": "path: item_id (int); body: JSON (fields not yet documented)", + "purpose": "Add freshly printed stock. Body: {quantity, badge}.", + "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/restock -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "badge": "", + "quantity": 10 + }, + "responseexample": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": null, + "imageurl": null, + "isactive": true, + "islowstock": false, + "itemcode": "3DP-9001", + "itemdescription": null, + "itemname": "Test clip", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 10 + }, + "message": "Stock added", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/printedparts/items//restore", + "auth": "permission:printedparts.delete", + "params": "path: item_id (int); body: JSON (fields not yet documented)", + "purpose": "Bring a retired item back; code, photo, and history are intact.", + "example": "curl -X POST http://localhost:5001/api/printedparts/items/1/restore -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": null, + "imageurl": null, + "isactive": true, + "islowstock": true, + "itemcode": "3DP-9001", + "itemdescription": null, + "itemname": "Test clip", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 0 + }, + "message": "Printed item restored", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printedparts/kiosk/item/", + "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", + "params": "path: itemcode (string)", + "purpose": "Item summary for a scanned bin barcode. Kiosk-token gated.", + "example": "curl http://localhost:5001/api/printedparts/kiosk/item/x", + "responseexample": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": "WJRP0117", + "imageurl": null, + "isactive": true, + "islowstock": true, + "itemcode": "3DP0001", + "itemdescription": null, + "itemname": "Gage block holder", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printedparts/kiosk/provisioning-link", + "auth": "permission:settings.edit", + "params": "not documented", + "purpose": "The URL that provisions a screen, token included, for an administrator.", + "example": "curl http://localhost:5001/api/printedparts/kiosk/provisioning-link -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "POST", + "path": "/api/printedparts/kiosk/take", + "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Take parts from a bin. Body: {itemcode, badge, quantity}.", + "example": "curl -X POST http://localhost:5001/api/printedparts/kiosk/take -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "badge": "", + "itemcode": "WJRP7000|3", + "quantity": 1 + }, + "responseexample": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": "WJRP7000", + "imageurl": null, + "isactive": true, + "islowstock": false, + "itemcode": "3DP-7000", + "itemdescription": null, + "itemname": "Rev part", + "latestrevision": null, + "lowstockthreshold": 2, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 8 + }, + "message": "Took 1, 8 left", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/printedparts/reports/by-person", + "auth": "permission:printedparts.view", + "params": "not documented", + "purpose": "Takes grouped by employee, optionally bounded by ?days= (default 30).", + "example": "curl http://localhost:5001/api/printedparts/reports/by-person -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "days", + "type": "integer", + "required": false, + "default": 30 + }, + { + "name": "format", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "columns": [ + "employeesso", + "employeename", + "takes", + "" + ], + "days": 30, + "rows": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printedparts/reports/consumption", + "auth": "permission:printedparts.view", + "params": "not documented", + "purpose": "Takes per item, optionally bounded by ?days= (default 30).", + "example": "curl http://localhost:5001/api/printedparts/reports/consumption -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "days", + "type": "integer", + "required": false, + "default": 30 + }, + { + "name": "format", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "columns": [ + "itemcode", + "itemname", + "takes", + "" + ], + "days": 30, + "rows": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printedparts/reports/stock", + "auth": "permission:printedparts.view", + "params": "not documented", + "purpose": "Stock levels with low-stock flags and the cache-vs-ledger reconcile.", + "example": "curl http://localhost:5001/api/printedparts/reports/stock -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "format", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "columns": [ + "itemcode", + "itemname", + "binlocation", + "" + ], + "rows": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "plugin-printers", + "endpoints": [ + { + "method": "GET", + "path": "/api/printers", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "List all printers with filtering and pagination.", + "example": "curl http://localhost:5001/api/printers -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "assetnumber", + "type": "string", + "required": false + }, + { + "name": "businessunit_id", + "type": "integer", + "required": false + }, + { + "name": "businessunitid", + "type": "integer", + "required": false + }, + { + "name": "dir", + "type": "string", + "required": false, + "default": "asc" + }, + { + "name": "location_id", + "type": "integer", + "required": false + }, + { + "name": "locationid", + "type": "integer", + "required": false + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "sort", + "type": "string", + "required": false, + "default": "hostname" + }, + { + "name": "type_id", + "type": "integer", + "required": false + }, + { + "name": "typeid", + "type": "integer", + "required": false + }, + { + "name": "vendor_id", + "type": "integer", + "required": false + }, + { + "name": "vendorid", + "type": "integer", + "required": false + } + ], + "responseexample": { + "data": [ + { + "assetid": 1, + "assetnumber": "PR-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "printer", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "printer": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "installpath": null, + "isactive": true, + "iscolor": false, + "iscsf": false, + "isduplex": false, + "isnetwork": true, + "modelname": "ZT411", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "pin": null, + "printerid": 1, + "printertypeid": 1, + "printertypename": "Thermal", + "sharename": null, + "vendorid": null, + "windowsname": null + }, + "serialnumber": "", + "statusid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/printers", + "auth": "permission:printers.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create new printer (creates both Asset and Printer records).", + "example": "curl -X POST http://localhost:5001/api/printers -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "assetnumber": "CSF01-Materials-HP", + "hostname": "", + "installpath": "", + "mapx": 120, + "mapy": 240 + }, + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "SpoolsInspection-Xerox", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "printer", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "printer": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "installpath": null, + "isactive": true, + "iscolor": false, + "iscsf": false, + "isduplex": false, + "isnetwork": true, + "modelname": "VersaLink C7125", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "pin": null, + "printerid": 1, + "printertypeid": null, + "sharename": null, + "vendorfrommodel": true, + "vendorid": null, + "vendorname": "Xerox", + "windowsname": null + }, + "serialnumber": "", + "statusid": 1 + }, + "message": "Printer created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/printers/", + "auth": "permission:printers.delete", + "params": "path: printer_id (int)", + "purpose": "Delete (soft delete) printer.", + "example": "curl -X DELETE http://localhost:5001/api/printers/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/printers/", + "auth": "permission:printers.view", + "params": "path: printer_id (int)", + "purpose": "Get a single printer with full details.", + "example": "curl http://localhost:5001/api/printers/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "PR-2001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "printer", + "businessunitid": null, + "communications": [], + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "drivers": [], + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "printer": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "imageurl": "/api/models/images/model-1.png", + "installpath": null, + "isactive": true, + "iscolor": false, + "iscsf": false, + "isduplex": false, + "isnetwork": true, + "modelname": "IMG-MODEL-1", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "pin": null, + "printerid": 1, + "printertypeid": null, + "sharename": null, + "vendorid": null, + "windowsname": null + }, + "serialnumber": "", + "statusid": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/printers/", + "auth": "permission:printers.edit", + "params": "path: printer_id (int); body: JSON (fields not yet documented)", + "purpose": "Update printer (both Asset and Printer records).", + "example": "curl -X PUT http://localhost:5001/api/printers/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "gaugelabreference": "GL-2", + "maintenancereference": "MNT-2" + }, + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "AST-printer", + "assettypecolor": null, + "assettypeid": 2, + "assettypename": "printer", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-2", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": "MNT-2", + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "printer": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "installpath": null, + "isactive": true, + "iscolor": false, + "iscsf": false, + "isduplex": false, + "isnetwork": true, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "pin": null, + "printerid": 1, + "printertypeid": null, + "sharename": null, + "vendorid": null, + "windowsname": null + }, + "serialnumber": "", + "statusid": 1 + }, + "message": "Printer updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/printers//supplies", + "auth": "permission:printers.view", + "params": "path: printer_id (int)", + "purpose": "Get supply levels from Zabbix (real-time lookup).", + "example": "curl http://localhost:5001/api/printers/1/supplies -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/printers/assignments/for-asset/", + "auth": "permission:printers.view", + "params": "path: asset_id (int)", + "purpose": "What THIS asset is assigned, without inheritance.", + "example": "curl http://localhost:5001/api/printers/assignments/for-asset/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "assetid": 4, + "defaultprinterassetid": null, + "printerassetids": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/printers/assignments/for-asset/", + "auth": "permission:printers.edit", + "params": "path: asset_id (int); body: JSON (fields not yet documented)", + "purpose": "Reconcile one asset's whole printer assignment in a single call.", + "example": "curl -X PUT http://localhost:5001/api/printers/assignments/for-asset/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "defaultprinterassetid": 4, + "printerassetids": [ + 4, + 5 + ] + }, + "responseexample": { + "data": { + "assetid": 3, + "defaultprinterassetid": 4, + "printerassetids": [ + 4, + 5 + ] + }, + "message": "Printer assignment updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/printers/assignments/seed-from-observed/", + "auth": "permission:printers.edit", + "params": "path: asset_id (int); body: JSON (fields not yet documented)", + "purpose": "Write what a PC observed as the assignment of the asset in the path.", + "example": "curl -X POST http://localhost:5001/api/printers/assignments/seed-from-observed/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/printers/by-asset/", + "auth": "permission:printers.view", + "params": "path: asset_id (int)", + "purpose": "Get printer data by asset ID.", + "example": "curl http://localhost:5001/api/printers/by-asset/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/printers/dashboard/summary", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "Get printer dashboard summary data.", + "example": "curl http://localhost:5001/api/printers/dashboard/summary -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "bytype": [], + "byvendor": [], + "criticalsupplies": 0, + "lowsupplies": 0, + "online": 0, + "total": 0, + "totalprinters": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/dashboard/supplies", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "Printers needing a cartridge, flattened to one row per printer.", + "example": "curl http://localhost:5001/api/printers/dashboard/supplies -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "rows": [ + { + "iscritical": true, + "levelid": null, + "location": "Shop floor", + "mapx": null, + "mapy": null, + "printerid": 2, + "printername": "Bravo", + "supplies": [ + { + "level": "critical", + "text": "Black Toner 0%", + "title": "No part number on file for this model" + } + ], + "worstremaining": 0 + }, + { + "iscritical": true, + "levelid": null, + "location": "Shop floor", + "mapx": null, + "mapy": null, + "printerid": 3, + "printername": "Charlie", + "supplies": [ + { + "level": "critical", + "text": "Black Toner 2%", + "title": "No part number on file for this model" + } + ], + "worstremaining": 2 + }, + { + "iscritical": true, + "levelid": null, + "location": "Shop floor", + "mapx": null, + "mapy": null, + "printerid": 1, + "printername": "Alpha", + "supplies": [ + { + "level": "critical", + "text": "Black Toner 4%", + "title": "No part number on file for this model" + } + ], + "worstremaining": 4 + }, + "" + ], + "unavailable": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/drivers", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "List printer drivers. ?active=false includes inactive ones.", + "example": "curl http://localhost:5001/api/printers/drivers -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + } + ], + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/printers/drivers", + "auth": "permission:printers.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: printers_asset.create_driver has no docstring.", + "example": "curl -X POST http://localhost:5001/api/printers/drivers -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "drivername": "HP Universal Printing PCL 6", + "location": "", + "name": "HP universal", + "vendorid": 1 + }, + "responseexample": { + "data": { + "description": null, + "driverid": 1, + "drivername": "HP Universal Printing PCL 6", + "isactive": true, + "location": "", + "modelname": null, + "modelnumberid": null, + "name": "HP universal", + "vendorid": 1 + }, + "message": "Driver created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/printers/drivers/", + "auth": "permission:printers.delete", + "params": "path: driver_id (int)", + "purpose": "UNDOCUMENTED: printers_asset.delete_driver has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/printers/drivers/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/printers/drivers/", + "auth": "permission:printers.edit", + "params": "path: driver_id (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: printers_asset.update_driver has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/printers/drivers/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "drivername": "Xerox Global Print Driver PCL6", + "vendorid": 2 + }, + "responseexample": { + "data": { + "description": null, + "driverid": 1, + "drivername": "Xerox Global Print Driver PCL6", + "isactive": true, + "location": "", + "modelname": null, + "modelnumberid": null, + "name": "Xerox universal", + "vendorid": 2 + }, + "message": "Driver updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/printers/for-host/", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "path: hostname (string)", + "purpose": "Printers assigned to a PC, by hostname, with what it takes to install one.", + "example": "curl http://localhost:5001/api/printers/for-host/x -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "1001", + "defaultprinterid": null, + "hostname": "", + "printers": [ + { + "assetid": 4, + "driverid": null, + "driverlocation": null, + "drivername": null, + "hostname": "", + "inheritedfromassetid": 3, + "installpath": null, + "ipaddress": "", + "isdefault": false, + "port": null, + "printerid": 1, + "queuename": "PRINTER-A", + "sharename": null, + "windowsname": "PRINTER-A" + }, + { + "assetid": 5, + "driverid": null, + "driverlocation": null, + "drivername": null, + "hostname": "", + "inheritedfromassetid": 3, + "installpath": null, + "ipaddress": "", + "isdefault": false, + "port": null, + "printerid": 2, + "queuename": "PRINTER-B", + "sharename": null, + "windowsname": "PRINTER-B" + }, + { + "assetid": 6, + "driverid": null, + "driverlocation": null, + "drivername": null, + "hostname": "", + "inheritedfromassetid": 3, + "installpath": null, + "ipaddress": "", + "isdefault": false, + "port": null, + "printerid": 3, + "queuename": "PRINTER-C", + "sharename": null, + "windowsname": "PRINTER-C" + } + ], + "source": "inherited" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/install-batch", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "Generate a Windows .bat that installs the selected printers.", + "example": "curl http://localhost:5001/api/printers/install-batch -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "printerids", + "type": "string", + "required": false + } ] - } -] + }, + { + "method": "GET", + "path": "/api/printers/install-list", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "Flat, unpaginated list of network printers for the printer installer.", + "example": "curl http://localhost:5001/api/printers/install-list -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "format", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [ + { + "hostname": "", + "installpath": "", + "ipaddress": "", + "iscsf": false, + "levelid": null, + "locationname": null, + "machinenumber": "CSF01-Materials-HP", + "mapx": 120, + "mapy": 240, + "modelnumber": null, + "name": "CSF01-Materials-HP", + "printerid": 1, + "sharename": null, + "vendorname": "", + "windowsname": null + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/lookup", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "Find a printer by IP or FQDN. Parity with the classic printerlookup.asp.", + "example": "curl http://localhost:5001/api/printers/lookup -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "fqdn", + "type": "string", + "required": false + }, + { + "name": "ip", + "type": "string", + "required": false + } + ] + }, + { + "method": "GET", + "path": "/api/printers/lowsupplies", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "Get printers with low or critical supply levels.", + "example": "curl http://localhost:5001/api/printers/lowsupplies -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "printers": [], + "summary": { + "critical": 0, + "low": 0, + "total_checked": 0 + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/models", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "List models with a supply count, for the supply-management picker.", + "example": "curl http://localhost:5001/api/printers/models -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + }, + { + "name": "vendor_id", + "type": "integer", + "required": false + }, + { + "name": "vendorid", + "type": "integer", + "required": false + }, + { + "name": "withsupplies", + "type": "string", + "required": false, + "default": "" + } + ], + "responseexample": { + "data": [ + { + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "supplycount": 1, + "vendor": "TestVendor", + "vendorid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/models//supplies", + "auth": "permission:printers.view", + "params": "path: modelnumberid (int)", + "purpose": "List all supplies mapped to a model.", + "example": "curl http://localhost:5001/api/printers/models/1/supplies -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "supplies": [ + { + "capacitytier": "standard", + "color": "black", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "marketingname": "414A Black", + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "modelsupplyid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "pageyield": 2400, + "partnumber": "W2020A", + "supplytype": "toner" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/printers/models//supplies", + "auth": "permission:printers.create", + "params": "path: modelnumberid (int); body: JSON (fields not yet documented)", + "purpose": "Add a supply to a model.", + "example": "curl -X POST http://localhost:5001/api/printers/models/1/supplies -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "capacitytier": "standard", + "color": "black", + "marketingname": "414A Black", + "pageyield": 2400, + "partnumber": "W2020A", + "supplytype": "toner" + }, + "responseexample": { + "data": { + "capacitytier": "standard", + "color": "black", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "marketingname": "414A Black", + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "modelsupplyid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "pageyield": 2400, + "partnumber": "W2020A", + "supplytype": "toner" + }, + "message": "Supply added", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/printers/observed/", + "auth": "permission:printers.view", + "params": "path: hostname (string)", + "purpose": "What a host last reported, each queue judged against what it is assigned.", + "example": "curl http://localhost:5001/api/printers/observed/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/printers/observed/for-asset/", + "auth": "permission:printers.view", + "params": "path: asset_id (int)", + "purpose": "The same comparison, reached from an asset page: one block per host.", + "example": "curl http://localhost:5001/api/printers/observed/for-asset/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "assetid": 1, + "assetnumber": "1001", + "hosts": [ + { + "assetid": 1, + "assetnumber": "1001", + "hostname": "", + "observedat": "2026-01-01T00:00:00.000000", + "queues": [ + { + "classification": "extra", + "driftfields": [], + "drivername": "HP Universal Printing PS", + "expecteddrivername": null, + "expectedportaddress": null, + "expectedqueuename": null, + "inheritedfromassetid": null, + "isassigneddefault": false, + "isdefault": true, + "isshared": false, + "portaddress": "", + "portname": "IP_10.20.0.11", + "printerassetid": 5, + "printerid": 1, + "printername": "Bay label printer", + "queuename": "PRINTER-A" + }, + { + "classification": "extra", + "driftfields": [], + "drivername": "HP Universal Printing PS", + "expecteddrivername": null, + "expectedportaddress": null, + "expectedqueuename": null, + "inheritedfromassetid": null, + "isassigneddefault": false, + "isdefault": false, + "isshared": false, + "portaddress": "", + "portname": "IP_10.20.0.12", + "printerassetid": 6, + "printerid": 2, + "printername": "Bay laser printer", + "queuename": "PRINTER-B" + }, + { + "classification": "unknown", + "driftfields": [], + "drivername": "HP Universal Printing PS", + "expecteddrivername": null, + "expectedportaddress": null, + "expectedqueuename": null, + "inheritedfromassetid": null, + "isassigneddefault": false, + "isdefault": false, + "isshared": false, + "portaddress": "", + "portname": "IP_10.20.0.99", + "printerassetid": null, + "printerid": null, + "printername": null, + "queuename": "Reception Copier" + } + ], + "seedcandidate": { + "defaultprinterassetid": 5, + "printerassetids": [ + 5, + 6 + ], + "skipped": [ + { + "drivername": "HP Universal Printing PS", + "isdefault": false, + "portaddress": "", + "portname": "IP_10.20.0.99", + "queuename": "Reception Copier" + } + ] + }, + "source": "none", + "summary": { + "drifted": 0, + "extra": 2, + "matching": 0, + "missing": 0, + "unknown": 1 + } + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/pc-default", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "not documented", + "purpose": "Default printer for a PC, by machine (asset) number.", + "example": "curl http://localhost:5001/api/printers/pc-default -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "format", + "type": "string", + "required": false + }, + { + "name": "machine", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": { + "printerid": 1, + "windowsname": "HP-CSF04-Materials" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "DELETE", + "path": "/api/printers/supplies/", + "auth": "permission:printers.delete", + "params": "path: modelsupplyid (int)", + "purpose": "Delete a model supply.", + "example": "curl -X DELETE http://localhost:5001/api/printers/supplies/1 -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "message": "Supply deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PUT", + "path": "/api/printers/supplies/", + "auth": "permission:printers.edit", + "params": "path: modelsupplyid (int); body: JSON (fields not yet documented)", + "purpose": "Update a model supply.", + "example": "curl -X PUT http://localhost:5001/api/printers/supplies/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "capacitytier": "high", + "marketingname": "414X Black" + }, + "responseexample": { + "data": { + "capacitytier": "high", + "color": "black", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "marketingname": "414X Black", + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "modelsupplyid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "pageyield": null, + "partnumber": "W2020A", + "supplytype": "toner" + }, + "message": "Supply updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/printers/supplies/forecast", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "Days-to-empty and replacement counts per printer.", + "example": "curl http://localhost:5001/api/printers/supplies/forecast -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "days", + "type": "integer", + "required": false, + "default": 90 + } + ], + "responseexample": { + "data": { + "available": false, + "cartridges": [], + "days": 90, + "horizondays": 14, + "orderlist": [], + "reason": "Zabbix is not configured or not reachable", + "unestimated": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/supplies/meta", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "Allowed values for supply type, color, and capacity tier (for the UI).", + "example": "curl http://localhost:5001/api/printers/supplies/meta -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "capacitytiers": [ + "standard", + "high", + "extrahigh", + "" + ], + "colors": [ + "black", + "cyan", + "magenta", + "" + ], + "supplytypes": [ + "toner", + "drum", + "waste", + "" + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/printers/supplies/refresh", + "auth": "permission:printers.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Clear cached Zabbix supply data so the next read pulls fresh values.", + "example": "curl -X POST http://localhost:5001/api/printers/supplies/refresh -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": {}, + "responseexample": { + "message": "Supply cache cleared", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/printers/types", + "auth": "permission:printers.view", + "params": "not documented", + "purpose": "List all printer types.", + "example": "curl http://localhost:5001/api/printers/types -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/printers/types", + "auth": "permission:printers.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Create a new printer type.", + "example": "curl -X POST http://localhost:5001/api/printers/types -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/printers/types/", + "auth": "permission:printers.delete", + "params": "path: type_id (int)", + "purpose": "Delete a printer type. Refused if any printer still uses it.", + "example": "curl -X DELETE http://localhost:5001/api/printers/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/printers/types/", + "auth": "permission:printers.view", + "params": "path: type_id (int)", + "purpose": "Get a single printer type.", + "example": "curl http://localhost:5001/api/printers/types/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/printers/types/", + "auth": "permission:printers.edit", + "params": "path: type_id (int); body: JSON (fields not yet documented)", + "purpose": "Update a printer type.", + "example": "curl -X PUT http://localhost:5001/api/printers/types/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + } + ] + }, + { + "surface": "plugin-slides", + "endpoints": [ + { + "method": "GET", + "path": "/api/slides/", + "auth": "permission:slides.view or slides.manage", + "params": "path: surface (string)", + "purpose": "UNDOCUMENTED: slides.list_slides has no docstring.", + "example": "curl http://localhost:5001/api/slides/x -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "PATCH", + "path": "/api/slides//", + "auth": "permission:slides.manage", + "params": "path: surface (string), slideid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: slides.update_slide has no docstring.", + "example": "curl -X PATCH http://localhost:5001/api/slides/x/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/slides//delete", + "auth": "permission:slides.manage", + "params": "path: surface (string); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: slides.delete_slides has no docstring.", + "example": "curl -X POST http://localhost:5001/api/slides/x/delete -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/slides//order", + "auth": "permission:slides.manage", + "params": "path: surface (string); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: slides.reorder_slides has no docstring.", + "example": "curl -X POST http://localhost:5001/api/slides/x/order -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/slides//upload", + "auth": "permission:slides.manage", + "params": "path: surface (string); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: slides.upload_slides has no docstring.", + "example": "curl -X POST http://localhost:5001/api/slides/x/upload -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/slides/feed", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "not documented", + "purpose": "Flat playlist for a surface. NOT wrapped in the success_response envelope so the screensaver's existing parser needs no change.", + "example": "curl http://localhost:5001/api/slides/feed", + "queryparams": [ + { + "name": "surface", + "type": "string", + "required": false, + "default": "lobby" + } + ], + "responseexample": { + "basepath": "/api/slides/img/lobby/", + "interval": 10, + "slides": [], + "success": true, + "surface": "lobby" + } + }, + { + "method": "GET", + "path": "/api/slides/img//", + "auth": "none (reviewed: named in the public-read or mutation sweep)", + "params": "path: surface (string), filename (path)", + "purpose": "Serve a slide image with a path-traversal guard.", + "example": "curl http://localhost:5001/api/slides/img/x/example.png" + } + ] + }, + { + "surface": "plugin-tools", + "endpoints": [ + { + "method": "POST", + "path": "/api/tools/secrets", + "auth": "jwt-optional (works signed out; the handler decides what shows)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Store an already-encrypted secret and return its token.", + "example": "curl -X POST http://localhost:5001/api/tools/secrets -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "ciphertext": "", + "iv": "MTIzNDU2Nzg5MDEy", + "views": 100 + }, + "responseexample": { + "data": { + "createddate": "2026-01-01T00:00:00.000000", + "expiresat": "2026-01-01T00:00:00.000000", + "token": "", + "viewcount": 0, + "viewsremaining": 100 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/tools/secrets/", + "auth": "none (the unguessable token in the path is the authorisation)", + "params": "path: token (string)", + "purpose": "Whether a link is still live, WITHOUT spending it.", + "example": "curl http://localhost:5001/api/tools/secrets/x", + "responseexample": { + "data": { + "available": false + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/tools/secrets/", + "auth": "none (the unguessable token in the path is the authorisation; redeeming spends the secret)", + "params": "path: token (string); body: JSON (fields not yet documented)", + "purpose": "Hand over the ciphertext once, then spend the view.", + "example": "curl -X POST http://localhost:5001/api/tools/secrets/x -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "ciphertext": "", + "iv": "MTIzNDU2Nzg5MDEy" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "plugin-usb", + "endpoints": [ + { + "method": "GET", + "path": "/api/usb", + "auth": "permission:usb.view", + "params": "not documented", + "purpose": "List USB devices with checkout status.", + "example": "curl http://localhost:5001/api/usb -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + }, + { + "name": "search", + "type": "string", + "required": false, + "default": "" + }, + { + "name": "status", + "type": "string", + "required": false, + "default": "" + } + ] + }, + { + "method": "POST", + "path": "/api/usb", + "auth": "permission:usb.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "Add a device (starts checked-in).", + "example": "curl -X POST http://localhost:5001/api/usb -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/usb/", + "auth": "permission:usb.view", + "params": "path: device_id (string)", + "purpose": "Get a single device plus its last 20 check-in/out log rows.", + "example": "curl http://localhost:5001/api/usb/x -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/usb/", + "auth": "permission:usb.edit", + "params": "path: device_id (string); body: JSON (fields not yet documented)", + "purpose": "Edit device_desc / device_owner / locker_location / status.", + "example": "curl -X PUT http://localhost:5001/api/usb/x -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/usb//checkin", + "auth": "permission:usb.create", + "params": "path: device_id (string); body: JSON (fields not yet documented)", + "purpose": "Check a device back in from a badge.", + "example": "curl -X POST http://localhost:5001/api/usb/x/checkin -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "POST", + "path": "/api/usb//checkout", + "auth": "permission:usb.create", + "params": "path: device_id (string); body: JSON (fields not yet documented)", + "purpose": "Check a device out to a badge.", + "example": "curl -X POST http://localhost:5001/api/usb/x/checkout -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "readsbody": true + }, + { + "method": "GET", + "path": "/api/usb//history", + "auth": "permission:usb.view", + "params": "path: device_id (string)", + "purpose": "Paginated check-in/out log for one device.", + "example": "curl http://localhost:5001/api/usb/x/history -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + } + ] + }, + { + "method": "POST", + "path": "/api/usb//retire", + "auth": "permission:usb.edit", + "params": "path: device_id (string); body: JSON (fields not yet documented)", + "purpose": "Retire a device (status -> retired).", + "example": "curl -X POST http://localhost:5001/api/usb/x/retire -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "GET", + "path": "/api/usb/checkouts", + "auth": "permission:usb.view", + "params": "not documented", + "purpose": "List check-out log rows.", + "example": "curl http://localhost:5001/api/usb/checkouts -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "" + }, + { + "name": "page", + "type": "integer", + "required": false, + "default": 1 + }, + { + "name": "per_page", + "type": "integer", + "required": false + }, + { + "name": "perpage", + "type": "integer", + "required": false + } + ] + }, + { + "method": "GET", + "path": "/api/usb/checkouts/active", + "auth": "permission:usb.view", + "params": "not documented", + "purpose": "List the latest check-out log row for every currently checked-out device.", + "example": "curl http://localhost:5001/api/usb/checkouts/active -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "badge", + "type": "string", + "required": false, + "default": "" + } + ] + }, + { + "method": "POST", + "path": "/api/usb/kiosk/checkin", + "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Check a device in at the kiosk. Body: {device_id, badge, forsomeoneelse}.", + "example": "curl -X POST http://localhost:5001/api/usb/kiosk/checkin -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "badge": "", + "device_id": "USB-1", + "forsomeoneelse": true + }, + "responseexample": { + "data": { + "device_id": "USB-1" + }, + "message": "USB-1 checked in", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/usb/kiosk/checkout", + "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Check a device out at the kiosk. Body: {device_id, badge}.", + "example": "curl -X POST http://localhost:5001/api/usb/kiosk/checkout -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "badge": "", + "device_id": "USB-1" + }, + "responseexample": { + "data": { + "device_id": "USB-1", + "holdername": "Dana Reyes" + }, + "message": "USB-1 checked out to Dana Reyes", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/usb/kiosk/device/", + "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", + "params": "path: device_id (string)", + "purpose": "What the kiosk shows after a device is scanned.", + "example": "curl http://localhost:5001/api/usb/kiosk/device/x", + "responseexample": { + "data": { + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "holdername": "Dana Reyes", + "locker_location": null, + "status": "checked-out" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/usb/kiosk/others", + "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", + "params": "body: JSON (fields not yet documented)", + "purpose": "Drives checked out to OTHER people, with holder names. Body: {badge}.", + "example": "curl -X POST http://localhost:5001/api/usb/kiosk/others -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "badge": "" + }, + "responseexample": { + "data": [ + { + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "holdername": "Dana Reyes", + "locker_location": null + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/usb/kiosk/provisioning-link", + "auth": "permission:settings.edit", + "params": "not documented", + "purpose": "The URL that provisions a screen, token included, for an administrator.", + "example": "curl http://localhost:5001/api/usb/kiosk/provisioning-link -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "expiresinminutes": 30, + "url": "/api/usb/kiosk/setup?code=" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/usb/kiosk/session", + "auth": "api-key-optional (kiosk: the per-device token in the X-Kiosk-Token header, OR a caller address inside the site's kiosk CIDR allowlist - an allowlisted caller sends no credential; 404 while the site's kiosk flag is off)", + "params": "body: JSON (fields not yet documented)", + "purpose": "What one badge may do right now. Body: {badge}.", + "example": "curl -X POST http://localhost:5001/api/usb/kiosk/session -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "badge": "" + }, + "responseexample": { + "data": { + "available": [ + { + "device_desc": "Second", + "device_id": "USB-2", + "locker_location": null + } + ], + "name": "Dana Reyes", + "otherscount": 0, + "yours": [ + { + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "locker_location": null + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "GET", + "path": "/api/usb/kiosk/setup", + "auth": "setup-code (single-use kiosk setup code in ?code=, issued by the permission-gated provisioning link; spent on any attempt, 410 once used or expired)", + "params": "not documented", + "purpose": "Trade a setup code for this browser's kiosk cookie, then open the kiosk.", + "example": "curl http://localhost:5001/api/usb/kiosk/setup", + "queryparams": [ + { + "name": "code", + "type": "string", + "required": false + } + ] + }, + { + "method": "GET", + "path": "/api/usb/reports/audit", + "auth": "permission:usb.view", + "params": "not documented", + "purpose": "Every check-out and check-in in the window, newest first.", + "example": "curl http://localhost:5001/api/usb/reports/audit -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "columns": [ + "timestamp", + "action", + "device_id", + "" + ], + "days": 365, + "rows": [ + { + "action": "check-in", + "badge": "", + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "locker_location": "", + "name": "Dana Reyes", + "sanitized": "", + "scanned_viruses": "", + "timestamp": "2026-01-01T00:00:00.000000" + }, + { + "action": "check-out", + "badge": "", + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "locker_location": "", + "name": "Dana Reyes", + "sanitized": "", + "scanned_viruses": "", + "timestamp": "2026-01-01T00:00:00.000000" + }, + { + "action": "check-out", + "badge": "", + "device_desc": "Red SanDisk", + "device_id": "USB-2", + "locker_location": "", + "name": "Sam Okafor", + "sanitized": "", + "scanned_viruses": "", + "timestamp": "2026-01-01T00:00:00.000000" + } + ], + "summary": { + "checkins": 1, + "checkouts": 2, + "devices": 2, + "events": 3, + "people": 2 + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + }, + { + "surface": "plugin-warranty", + "endpoints": [ + { + "method": "GET", + "path": "/api/warranty", + "auth": "permission:warranty.view", + "params": "not documented", + "purpose": "List warranties. Filters: ?status=, ?assetid=, ?active=false.", + "example": "curl http://localhost:5001/api/warranty -H \"Authorization: Bearer $TOK\"", + "queryparams": [ + { + "name": "active", + "type": "string", + "required": false, + "default": "true" + }, + { + "name": "assetid", + "type": "integer", + "required": false + }, + { + "name": "servicetag", + "type": "string", + "required": false + }, + { + "name": "status", + "type": "string", + "required": false + }, + { + "name": "vendor", + "type": "string", + "required": false + } + ], + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/warranty", + "auth": "permission:warranty.create", + "params": "body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: warranty.create_warranty has no docstring.", + "example": "curl -X POST http://localhost:5001/api/warranty -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "enddate": "2026-01-01", + "servicetag": "", + "vendor": "Acme" + }, + "responseexample": { + "data": { + "assets": [], + "enddate": "2026-01-01", + "isactive": true, + "lastcheckeddate": null, + "notes": null, + "prooffilename": null, + "proofurl": null, + "provider": "manual", + "servicelevel": null, + "servicetag": "", + "startdate": null, + "status": "active", + "statuscolor": "#4CAF50", + "vendor": "Acme", + "warrantyid": 1 + }, + "message": "Warranty created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/warranty/", + "auth": "permission:warranty.delete", + "params": "path: warrantyid (int)", + "purpose": "UNDOCUMENTED: warranty.delete_warranty has no docstring.", + "example": "curl -X DELETE http://localhost:5001/api/warranty/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/warranty/", + "auth": "permission:warranty.view", + "params": "path: warrantyid (int)", + "purpose": "UNDOCUMENTED: warranty.get_warranty has no docstring.", + "example": "curl http://localhost:5001/api/warranty/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "PUT", + "path": "/api/warranty/", + "auth": "permission:warranty.edit", + "params": "path: warrantyid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: warranty.update_warranty has no docstring.", + "example": "curl -X PUT http://localhost:5001/api/warranty/1 -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "requestexample": { + "enddate": "" + }, + "responseexample": { + "data": { + "assets": [], + "enddate": null, + "isactive": true, + "lastcheckeddate": null, + "notes": null, + "prooffilename": null, + "proofurl": null, + "provider": "manual", + "servicelevel": null, + "servicetag": "", + "startdate": null, + "status": "unknown", + "statuscolor": "#9E9E9E", + "vendor": "Acme", + "warrantyid": 1 + }, + "message": "Warranty updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "DELETE", + "path": "/api/warranty//proof", + "auth": "permission:warranty.edit", + "params": "path: warrantyid (int)", + "purpose": "Remove a warranty's proof document.", + "example": "curl -X DELETE http://localhost:5001/api/warranty/1/proof -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "enddate": null, + "isactive": true, + "lastcheckeddate": null, + "notes": null, + "prooffilename": null, + "proofurl": null, + "provider": "manual", + "servicelevel": null, + "servicetag": "", + "startdate": null, + "status": "unknown", + "statuscolor": "#9E9E9E", + "vendor": "Dell", + "warrantyid": 1 + }, + "message": "Proof removed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/warranty//proof", + "auth": "permission:warranty.edit", + "params": "path: warrantyid (int); body: JSON (fields not yet documented)", + "purpose": "Upload (or replace) the proof-of-cover document for a warranty.", + "example": "curl -X POST http://localhost:5001/api/warranty/1/proof -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "responseexample": { + "data": { + "enddate": null, + "isactive": true, + "lastcheckeddate": null, + "notes": null, + "prooffilename": "Dell invoice 4471.pdf", + "proofurl": "/api/warranty/proof/warranty-1.pdf", + "provider": "manual", + "servicelevel": null, + "servicetag": "", + "startdate": null, + "status": "unknown", + "statuscolor": "#9E9E9E", + "vendor": "Dell", + "warrantyid": 1 + }, + "message": "Proof uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + }, + "readsbody": true + }, + { + "method": "POST", + "path": "/api/warranty//refresh", + "auth": "permission:warranty.edit", + "params": "path: warrantyid (int); body: JSON (fields not yet documented)", + "purpose": "UNDOCUMENTED: warranty.refresh_warranty has no docstring.", + "example": "curl -X POST http://localhost:5001/api/warranty/1/refresh -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'" + }, + { + "method": "GET", + "path": "/api/warranty/asset/", + "auth": "permission:warranty.view", + "params": "path: assetid (int)", + "purpose": "Warranties covering one asset (for the asset-detail panel).", + "example": "curl http://localhost:5001/api/warranty/asset/1 -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/warranty/dashboard/expiring", + "auth": "permission:warranty.view", + "params": "not documented", + "purpose": "Warranties running out, and ones that already have.", + "example": "curl http://localhost:5001/api/warranty/dashboard/expiring -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "GET", + "path": "/api/warranty/proof/", + "auth": "permission:warranty.view", + "params": "path: filename (path)", + "purpose": "Download a proof document.", + "example": "curl http://localhost:5001/api/warranty/proof/example.png -H \"Authorization: Bearer $TOK\"" + }, + { + "method": "GET", + "path": "/api/warranty/report", + "auth": "permission:warranty.view", + "params": "not documented", + "purpose": "Counts + lists bucketed by derived status.", + "example": "curl http://localhost:5001/api/warranty/report -H \"Authorization: Bearer $TOK\"", + "responseexample": { + "data": { + "buckets": { + "active": [], + "expired": [], + "expiring": [], + "unknown": [] + }, + "counts": { + "active": 0, + "expired": 0, + "expiring": 0, + "unknown": 0 + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + }, + { + "method": "POST", + "path": "/api/warranty/sync/dell", + "auth": "permission:warranty.edit", + "params": "body: JSON (fields not yet documented)", + "purpose": "Look up every asset serial (= Dell service tag) that has no warranty yet and create warranties for the ones Dell recognizes.", + "example": "curl -X POST http://localhost:5001/api/warranty/sync/dell -H \"Authorization: Bearer $TOK\" -H 'Content-Type: application/json' -d '{}'", + "queryparams": [ + { + "name": "all", + "type": "string", + "required": false, + "default": "false" + } + ], + "requestexample": {}, + "responseexample": { + "data": { + "candidates": 0, + "created": 0, + "matched": 0, + "updated": 0 + }, + "message": "No PCs need a warranty lookup.", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } + } + ] + } +] \ No newline at end of file diff --git a/docs/openapi.json b/docs/openapi.json index 0dd38f91..58ff11bf 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -280,7 +280,48 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "member token", + "resourcescopes": null, + "scopes": null, + "tokenid": 2, + "tokenprefix": "", + "userid": 2, + "username": "" + }, + { + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "admin token", + "resourcescopes": null, + "scopes": null, + "tokenid": 1, + "tokenprefix": "", + "userid": 1, + "username": "" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -298,7 +339,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "all", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "false" + } + } + ] }, "post": { "tags": [ @@ -316,7 +368,37 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "display svc", + "resourcescopes": [ + "gea-shopfloor-display" + ], + "scopes": [ + "geenforce.fetch" + ], + "secret": "", + "tokenid": 1, + "tokenprefix": "", + "userid": 1, + "warning": "Save this token now. It will not be shown again. Store it somewhere safe." + }, + "message": "Token created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -343,6 +425,15 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "name": "display svc", + "resourcescopes": [ + "gea-shopfloor-display" + ], + "scopes": [ + "geenforce.fetch" + ] } } } @@ -366,7 +457,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Token revoked", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -415,7 +516,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "test token", + "resourcescopes": null, + "scopes": [ + "applications.edit" + ], + "tokenid": 1, + "tokenprefix": "", + "userid": 1 + }, + "message": "Token updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -455,6 +582,11 @@ "type": "object", "additionalProperties": true, "description": "path: tokenid (int); body: JSON (fields not yet documented)" + }, + "example": { + "scopes": [ + "applications.edit" + ] } } } @@ -478,7 +610,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -496,7 +646,76 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "appname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "installable", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "showhidden", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "false" + } + } + ] }, "post": { "tags": [ @@ -514,7 +733,45 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Fleet App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": null, + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "policynote": "A configuration policy was created for this application, but it is not attached to any business policy and installs nothing until an admin adds it to one.", + "policyresult": "created", + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Application created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -541,6 +798,12 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "appname": "Monitored App", + "ismonitorable": true, + "monitorlaunchpath": "C:\\Vendor\\app.exe", + "monitorprocessname": "app.exe" } } } @@ -564,7 +827,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "deactivatedpolicies": [ + "Required app: Doomed", + "Hand made push" + ], + "policyresult": "kept" + }, + "message": "Application deleted; deactivated 2 policy(ies) that referenced it: Required app: Doomed, Hand made push", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -595,7 +875,22 @@ "type": "integer" } } - ] + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true, + "description": "This route reads a JSON body. The example is a request that worked." + }, + "example": { + "confirm": "OK" + } + } + } + } }, "get": { "tags": [ @@ -613,7 +908,50 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "TeamApp", + "contacts": [ + { + "name": "Alice", + "sso": "a01" + } + ], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": null, + "installedcount": 0, + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "knowledgebase": [], + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "supportteamid": 1, + "supportteamname": "Controls", + "teamurl": "https://sn.example/controls", + "versions": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -662,7 +1000,45 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": null, + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "policynote": "A configuration policy was created for this application, but it is not attached to any business policy and installs nothing until an admin adds it to one.", + "policyresult": "created", + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Application updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -702,6 +1078,11 @@ "type": "object", "additionalProperties": true, "description": "path: app_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "ismonitorable": false, + "monitorlaunchpath": "", + "monitorprocessname": "" } } } @@ -725,7 +1106,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -774,7 +1157,43 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": "/api/applications/image/application-1.png", + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Application image uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -837,7 +1256,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -888,7 +1309,43 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": null, + "installersha256": null, + "installpath": "", + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Installer removed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -937,7 +1394,48 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "appversionid": null, + "bytes": 130, + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "detectedversion": "", + "documentationpath": null, + "image": null, + "installersha256": "", + "installpath": "/api/applications/package/1/setup.exe", + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "sha256": "", + "supportteamid": null, + "supportteamname": null, + "teamurl": null, + "uploadedfilename": "setup.exe" + }, + "message": "Installer uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -1000,7 +1498,43 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appdescription": null, + "appid": 1, + "applicationlink": null, + "applicationnotes": null, + "appname": "Test App", + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "documentationpath": null, + "image": "/api/applications/image/application-1.png", + "installersha256": null, + "installpath": null, + "isactive": true, + "ishidden": false, + "isinstallable": false, + "islicenced": false, + "ismonitorable": false, + "isprinter": false, + "isrequired": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "monitorlaunchpath": null, + "monitorprocessname": null, + "supportteamid": null, + "supportteamname": null, + "teamurl": null + }, + "message": "Application reverted to record", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -1040,6 +1574,9 @@ "type": "object", "additionalProperties": true, "description": "path: app_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "confirm": "OK" } } } @@ -1063,7 +1600,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1112,7 +1651,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appid": 1, + "appversionid": 1, + "dateadded": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "notes": null, + "releasedate": null, + "sha256": "", + "silentargs": "/S /v/qn", + "version": "1.2.3" + }, + "message": "Version created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -1152,6 +1712,11 @@ "type": "object", "additionalProperties": true, "description": "path: app_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "sha256": "", + "silentargs": "/S /v/qn", + "version": "1.2.3" } } } @@ -1171,7 +1736,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1217,7 +1784,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "appdescription": null, + "appid": 1, + "appname": "Test App", + "appversionid": null, + "computerid": 1, + "id": 1, + "installeddate": "2026-01-01T00:00:00.000000Z", + "installedversion": "1.2.3", + "isactive": true + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -1266,7 +1855,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1329,7 +1920,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1386,7 +1979,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1457,7 +2052,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1509,7 +2106,57 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assetid": 1, + "assetnumber": "A-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "machine", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "mill", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "serialnumber": "", + "statusid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -1527,7 +2174,150 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "businessunit_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "dir", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "asc" + } + }, + { + "name": "include_type_data", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "false" + } + }, + { + "name": "location_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "assetnumber" + } + }, + { + "name": "status_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "statusid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "type", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "type_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "typeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -1545,7 +2335,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1595,7 +2387,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1644,7 +2438,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1674,6 +2470,15 @@ "schema": { "type": "integer" } + }, + { + "name": "include_type_data", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } } ] }, @@ -1693,7 +2498,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1756,7 +2563,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1807,7 +2616,66 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "incoming": [ + { + "createddate": "2026-01-01T00:00:00.000000Z", + "inheritsposition": true, + "isactive": true, + "isdirectional": true, + "label": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "relationshipid": 1, + "relationshiptypeid": 1, + "relationshiptypename": "controls", + "sourceasset": { + "assetid": 1, + "assetnumber": "PC-1", + "assettypecolor": null, + "assettypeid": 2, + "assettypename": "computer", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "serialnumber": "", + "statusid": 1 + }, + "sourceassetid": 1, + "targetassetid": 2 + } + ], + "outgoing": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -1858,7 +2726,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -1909,7 +2779,115 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assets": [ + { + "assetid": 1, + "assetnumber": "2007", + "assettype": "machine", + "assettypeid": 1, + "businessunit": null, + "businessunitid": null, + "displayname": "", + "levelid": null, + "location": null, + "locationid": null, + "mapx": 100, + "mapy": 100, + "name": null, + "primaryip": null, + "serialnumber": "", + "status": null, + "statuscolor": null, + "statusid": 1, + "typedata": { + "assetid": 1, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": null, + "machineid": 1, + "machinetypeid": null, + "maintenanceintervaldays": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": null, + "requiresmanualconfig": false, + "vendorid": null + } + }, + { + "assetid": 2, + "assetnumber": "2008", + "assettype": "machine", + "assettypeid": 1, + "businessunit": null, + "businessunitid": null, + "displayname": "", + "levelid": null, + "location": null, + "locationid": null, + "mapx": 110, + "mapy": 110, + "name": null, + "primaryip": null, + "serialnumber": "", + "status": null, + "statuscolor": null, + "statusid": 1, + "typedata": { + "assetid": 2, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": null, + "machineid": 2, + "machinetypeid": null, + "maintenanceintervaldays": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": null, + "requiresmanualconfig": false, + "vendorid": null + } + } + ], + "filters": { + "assettypes": [ + { + "assettype": "machine", + "assettypeid": 1, + "color": null, + "icon": null + } + ], + "businessunits": [], + "locations": [], + "statuses": [], + "subtypes": { + "Computer": [], + "Machine": [], + "Measuring Tool": [], + "Network Device": [], + "Printer": [] + } + }, + "total": 2 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -1927,7 +2905,57 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "assettype", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "statusid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "subtype", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] } }, "/api/assets/relationships": { @@ -1947,7 +2975,44 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "inheritsposition": true, + "isactive": true, + "label": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "propagated": [ + { + "createddate": "2026-01-01T00:00:00.000000Z", + "inheritsposition": true, + "isactive": true, + "label": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "relationshipid": 3, + "relationshiptypeid": 1, + "sourceassetid": 1, + "targetassetid": 3 + } + ], + "propagatedcount": 1, + "relationshipid": 2, + "relationshiptypeid": 1, + "sourceassetid": 1, + "targetassetid": 2 + }, + "message": "Relationship created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -1974,6 +3039,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "relationshiptypeid": 1, + "sourceassetid": 1, + "targetassetid": 2 } } } @@ -1997,7 +3067,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Relationship deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2048,7 +3128,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "color": null, + "description": null, + "isdirectional": false, + "propagatesthrough": [], + "relationshiptype": "WiFi", + "relationshiptypeid": 1 + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2084,7 +3183,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "color": null, + "description": null, + "isdirectional": true, + "propagatesthrough": [], + "relationshiptype": "Backup For", + "relationshiptypeid": 1 + }, + "message": "Relationship type created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2111,6 +3228,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "isdirectional": false, + "relationshiptype": "Dualpath" } } } @@ -2134,7 +3255,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2183,7 +3306,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "color": null, + "description": null, + "isdirectional": false, + "propagatesthrough": [], + "relationshiptype": "USB", + "relationshiptypeid": 1 + }, + "message": "Relationship type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2223,6 +3364,9 @@ "type": "object", "additionalProperties": true, "description": "path: type_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "isdirectional": false } } } @@ -2246,7 +3390,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2264,7 +3426,43 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -2282,7 +3480,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2332,7 +3532,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2381,7 +3583,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2430,7 +3634,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2493,7 +3699,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2511,7 +3735,43 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -2529,7 +3789,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2579,7 +3841,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2628,7 +3892,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2691,7 +3957,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 50, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2709,7 +3993,75 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "action", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "entitytype", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "from_date", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 50 + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "to_date", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "userid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] } }, "/api/auditlogs/entity/{entitytype}/{entityid}": { @@ -2729,7 +4081,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2788,7 +4142,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -2838,7 +4194,23 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "expired": 0, + "newest": "2026-01-01T00:00:00.000000", + "oldest": "2026-01-01T00:00:00.000000", + "retentiondays": 30, + "total": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2876,7 +4248,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "actions": {}, + "activeUsers": [], + "entities": {}, + "recentCount": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2914,7 +4301,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "mustchangepassword": "" + }, + "message": "Password changed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2941,6 +4341,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "current_password": "", + "new_password": "" } } } @@ -2960,7 +4364,39 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "access_token": "", + "expires_in": 3600, + "refresh_token": "", + "token_type": "", + "user": { + "email": "", + "firstname": "", + "lastname": "", + "mustchangepassword": "", + "permissions": [ + "endpoints.runscript", + "endpoints.agentupdate", + "endpoints.view", + "" + ], + "roles": [ + "upgradeoperatorrole" + ], + "userid": 2, + "username": "" + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -2981,6 +4417,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "password": "", + "username": "" } } } @@ -3004,7 +4444,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3054,7 +4496,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "email": "", + "firstname": "", + "lastname": "", + "mustchangepassword": "", + "permissions": [ + "assets.view", + "assets.create", + "assets.edit", + "" + ], + "roles": [ + "admin" + ], + "userid": 1, + "username": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -3092,7 +4560,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3143,7 +4613,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -3155,7 +4643,59 @@ } } } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "businessunit", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -3173,7 +4713,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3223,7 +4765,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3272,7 +4816,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3321,7 +4867,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3384,7 +4932,40 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "accessprotocols": [], + "action": "updated", + "assetid": 2, + "identityvalue": "LEGACYPC", + "machinelinks": [], + "measuringtoollinkcount": 0, + "measuringtoollinks": [], + "partmarkers": [ + { + "assetid": 3, + "assetnumber": "LEGACYPC-PARTMARKER", + "operationassetid": null + } + ], + "printerlinkcount": 0, + "printerlinks": [], + "status": "ok", + "warnings": [ + "mapped ComputerType not found: Shopfloor PC", + "machine number '0615' is this PC's own asset number; marker not filed under an operation. Rename the PC asset to its hostname, or create the operation asset." + ] + }, + "message": "computers collector updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -3424,6 +5005,32 @@ "type": "object", "additionalProperties": true, "description": "path: pluginname (string); body: JSON (fields not yet documented)" + }, + "example": { + "hostname": "", + "queues": [ + { + "drivername": "HP Universal Printing PS", + "isdefault": true, + "portaddress": "", + "portname": "IP_10.20.0.11", + "queuename": "PRINTER-A" + }, + { + "drivername": "HP Universal Printing PS", + "isdefault": false, + "portaddress": "", + "portname": "IP_10.20.0.12", + "queuename": "PRINTER-B" + }, + { + "drivername": "HP Universal Printing PS", + "isdefault": false, + "portaddress": "", + "portname": "IP_10.20.0.99", + "queuename": "Reception Copier" + } + ] } } } @@ -3447,7 +5054,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3485,7 +5094,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3535,7 +5146,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "errors": [], + "notfound": [ + "WJLEG01" + ], + "timestamp": "2026-01-01T00:00:00.000000", + "updated": 0 + }, + "message": "0 PC(s) updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -3562,6 +5191,13 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "pcs": [ + { + "hostname": "" + } + ] } } } @@ -3585,7 +5221,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "notfound": [ + "WJLEG01" + ], + "timestamp": "2026-01-01T00:00:00.000000", + "updated": 0 + }, + "message": "0 PC(s) heartbeat recorded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -3612,6 +5265,9 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "hostname": "" } } } @@ -3635,7 +5291,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3685,7 +5343,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "endpoints": [ + "POST /api/collector/", + "GET /api/collector/_schemas", + "POST /api/collector/pc", + "" + ], + "status": "ok", + "timestamp": "2026-01-01T00:00:00.000000" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -3723,7 +5400,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -3741,7 +5428,26 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "assettypeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -3759,7 +5465,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3809,7 +5517,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3858,7 +5568,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3921,7 +5633,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -3970,7 +5684,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4033,7 +5749,64 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "activeassets": 14, + "bystatus": { + "In Use": 14 + }, + "counts": { + "machines": 0, + "measuringtools": 14, + "networkdevices": 0, + "pcs": 0, + "printers": 0, + "total": 14 + }, + "countsactiveonly": true, + "dualpathcollapsed": true, + "inactiveexcluded": 0, + "inrepair": 0, + "recent": [ + { + "assetid": 14, + "assetnumber": "MT-MAP-TD", + "assettype": "measuring_tool", + "createddate": "2026-01-01T00:00:00.000000Z" + }, + { + "assetid": 13, + "assetnumber": "MT-MAP-MIC", + "assettype": "measuring_tool", + "createddate": "2026-01-01T00:00:00.000000Z" + }, + { + "assetid": 12, + "assetnumber": "MT-MAP-CAL", + "assettype": "measuring_tool", + "createddate": "2026-01-01T00:00:00.000000Z" + }, + "" + ], + "statuses": { + "In Use": 14 + }, + "totalassets": 14, + "totalmachines": 0, + "totalmeasuringtool": 14, + "totalnetwork": 0, + "totalpc": 0, + "totalprinter": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4072,7 +5845,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "cansearch": false + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4100,7 +5885,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "database": "healthy", + "status": "ok" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4133,7 +5931,41 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "icon": "layout-dashboard", + "name": "Dashboard", + "permission": "assets.view", + "position": 0, + "route": "/" + }, + { + "icon": "map", + "name": "Map", + "permission": "assets.view", + "position": 4, + "route": "/map" + }, + { + "icon": "bell", + "name": "Notifications", + "permission": "notifications.view", + "plugin": "notifications", + "position": 5, + "route": "/notifications" + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4165,7 +5997,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "bytype": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4203,7 +6047,40 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "activeassets": 0, + "bystatus": {}, + "counts": { + "machines": 0, + "measuringtools": 0, + "networkdevices": 0, + "pcs": 0, + "printers": 0, + "total": 0 + }, + "countsactiveonly": true, + "dualpathcollapsed": true, + "inactiveexcluded": 0, + "inrepair": 0, + "recent": [], + "statuses": {}, + "totalassets": 0, + "totalmachines": 0, + "totalmeasuringtool": 0, + "totalnetwork": 0, + "totalpc": 0, + "totalprinter": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4241,7 +6118,95 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "empty": "hide", + "endpoint": "/api/geenforce/dashboard/failures", + "id": "geenforce-failures", + "map": { + "detail": "entryname", + "link": "/pcs/{computerid}", + "meta": [ + { + "key": "message" + }, + { + "key": "exitcode", + "label": "exit" + } + ], + "timestamp": "receivedat", + "title": "hostname" + }, + "permission": "geenforce.manage", + "plugin": "geenforce", + "position": 10, + "render": "exceptions", + "severity": "critical", + "shortname": "Enforcement", + "title": "Enforcement failures", + "viewall": "/geenforce" + }, + { + "empty": "hide", + "endpoint": "/api/computers/dashboard/sharedmachines", + "id": "computers-sharedmachines", + "map": { + "detail": "pcs", + "link": "/machines/{assetid}", + "meta": [ + { + "key": "pccount", + "suffix": " PCs" + } + ], + "title": "machinenumber" + }, + "permission": "computers.view", + "plugin": "computers", + "position": 15, + "render": "exceptions", + "severity": "critical", + "shortname": "Duplicate machine no.", + "title": "Machine numbers on two PCs", + "viewall": "/machines" + }, + { + "empty": "hide", + "endpoint": "/api/endpoints/dashboard/stability", + "id": "endpoints-stability", + "map": { + "detail": "", + "link": "/pcs/{computerid}", + "meta": [ + { + "key": "eventcount", + "suffix": " events (48h)" + } + ], + "title": "hostname" + }, + "permission": "endpoints.fleet", + "plugin": "endpoints", + "position": 16, + "render": "exceptions", + "severity": "critical", + "shortname": "Crashes", + "title": "Endpoints with crashes or shutdowns", + "viewall": "/pcs" + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4279,7 +6244,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4315,7 +6290,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "businessunit": "Materials", + "businessunitid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "dashboarddefaultid": 1, + "description": "Materials lobby kiosk", + "displaypath": "/shopfloor", + "displayrole": "Dashboard", + "fqdn": "", + "ipaddress": "", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z" + }, + "message": "Mapping created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4342,6 +6340,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "businessunitid": 1, + "description": "Materials lobby kiosk", + "ipaddress": "" } } } @@ -4365,7 +6368,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Mapping deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4414,7 +6427,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "businessunit": "Materials", + "businessunitid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "dashboarddefaultid": 1, + "description": "moved", + "displaypath": "/shopfloor", + "displayrole": "Dashboard", + "fqdn": "", + "ipaddress": "", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z" + }, + "message": "Mapping updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4454,6 +6490,9 @@ "type": "object", "additionalProperties": true, "description": "path: default_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "description": "moved" } } } @@ -4473,7 +6512,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "businessunit": null, + "businessunitid": null, + "fqdn": "", + "ipaddress": "", + "path": "/parts-kiosk", + "role": "3DPrintRoom" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4485,7 +6541,25 @@ } } } - } + }, + "parameters": [ + { + "name": "fqdn", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "ipaddress", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/dashboarddefaults/visitor-location": { @@ -4501,7 +6575,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "businessunit": "Materials", + "businessunitid": 1, + "fqdn": "", + "ipaddress": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4513,7 +6602,25 @@ } } } - } + }, + "parameters": [ + { + "name": "fqdn", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "ipaddress", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/docs": { @@ -4529,7 +6636,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4557,7 +6666,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4585,7 +6696,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4613,7 +6726,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4645,7 +6760,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4663,7 +6796,59 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "locationname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -4681,7 +6866,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4731,7 +6918,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4780,7 +6969,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4829,7 +7020,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4892,7 +7085,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -4910,7 +7113,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + } + ] }, "post": { "tags": [ @@ -4928,7 +7142,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -4978,7 +7194,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5027,7 +7245,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5091,7 +7311,48 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "buildings": [ + { + "buildingid": 1, + "buildingname": "Public Works", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "levels": [ + { + "assetcount": 0, + "blueprintdark": null, + "blueprintlight": "floorplan.svg", + "buildingid": 1, + "buildingname": "Public Works", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "isdefault": false, + "levelid": 1, + "levelname": "Ground", + "mapheight": 2550, + "mapwidth": 3300, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "sortorder": 1 + } + ], + "modifieddate": "2026-01-01T00:00:00.000000Z", + "sortorder": 1 + } + ], + "defaultlevelid": 1, + "totalplaced": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -5121,7 +7382,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5171,7 +7434,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5221,7 +7486,31 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "blueprintdark": null, + "blueprintlight": "floorplan.svg", + "buildingid": 1, + "buildingname": "Public Works", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "isdefault": false, + "levelid": 1, + "levelname": "Ground", + "mapheight": 2550, + "mapwidth": 3300, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "sortorder": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -5264,7 +7553,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5325,7 +7616,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5388,7 +7681,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5452,7 +7747,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5506,7 +7803,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5556,7 +7855,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5617,7 +7918,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -5680,7 +7983,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "snapshotid": 1, + "updated": 1 + }, + "message": "1 position(s) saved", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -5707,6 +8024,16 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "positions": [ + { + "assetid": 1, + "levelid": 2, + "mapx": 42, + "mapy": 43 + } + ] } } } @@ -5730,7 +8057,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -5768,7 +8105,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "restored": 3, + "skippedassetids": [] + }, + "message": "3 marker(s) restored", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -5831,7 +8182,63 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetcount": 3, + "dryrun": false, + "levelid": 1, + "moves": [ + { + "assetid": 1, + "assetnumber": "M000", + "fromx": 100, + "fromy": 100, + "name": null, + "outofbounds": false, + "tox": 100, + "toy": 1550 + }, + { + "assetid": 2, + "assetnumber": "M001", + "fromx": 1500, + "fromy": 1200, + "name": null, + "outofbounds": true, + "tox": 1500, + "toy": 2650 + }, + { + "assetid": 3, + "assetnumber": "M002", + "fromx": 3200, + "fromy": 2500, + "name": null, + "outofbounds": true, + "tox": 3200, + "toy": 3950 + } + ], + "outofboundscount": 2, + "snapshotid": 1, + "tolevelid": 1, + "transform": { + "offsetx": 0.0, + "offsety": 1450.0, + "scalex": 1.0, + "scaley": 1.0 + } + }, + "message": "3 marker(s) moved; snapshot 1 can restore them", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -5858,6 +8265,24 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "dryrun": false, + "landmarks": [ + { + "fromx": 0, + "fromy": 0, + "tox": 0, + "toy": 1450 + }, + { + "fromx": 1000, + "fromy": 1000, + "tox": 1000, + "toy": 2450 + } + ], + "levelid": 1 } } } @@ -5881,7 +8306,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "updated": 1 + }, + "message": "1 marker(s) unverified", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -5908,6 +8346,12 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "assetids": [ + 1 + ], + "unverify": true } } } @@ -5931,7 +8375,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -5949,7 +8411,83 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "category", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "modelnumber", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "modeltype", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "vendor", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -5967,7 +8505,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6017,7 +8557,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6066,7 +8608,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6115,7 +8659,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6178,7 +8724,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "documentationurl": null, + "imageurl": null, + "isactive": true, + "modelnumber": "TESTMODEL-1", + "modelnumberid": 1, + "modeltypeid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "vendorid": null + }, + "message": "Model image removed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -6227,7 +8796,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "documentationurl": null, + "imageurl": "/api/models/image/model-1.jpg", + "isactive": true, + "modelnumber": "TESTMODEL-1", + "modelnumberid": 1, + "modeltypeid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "vendorid": null + }, + "message": "Model image uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -6286,7 +8878,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6332,7 +8926,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -6350,7 +8962,67 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "category", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "modeltype", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -6368,7 +9040,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6418,7 +9092,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6467,7 +9143,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6516,7 +9194,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6579,7 +9259,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -6597,7 +9295,67 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "osname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "osversion", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -6615,7 +9373,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6665,7 +9425,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6714,7 +9476,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6763,7 +9527,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6826,7 +9592,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6864,7 +9632,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -6928,7 +9698,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + "backups", + "computers", + "employees", + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -6960,7 +9745,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "routes": [ + { + "component": "drawn.vue", + "hub": "model-catalog", + "name": "drawn-route", + "path": "drawn", + "tab": "Drawn" + }, + { + "component": ".plugins-staged/computers/views/OperatingSystemsList.vue", + "hub": "model-catalog", + "name": "model-catalog-os", + "path": "operatingsystems", + "tab": "Operating Systems" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -6998,7 +9810,122 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assettypes": [ + "computer" + ], + "empty": "No agent report yet.", + "endpoint": "/api/endpoints/asset/{assetid}/status", + "group": "details", + "id": "endpoints-status", + "plugin": "endpoints", + "position": 10, + "render": "keyvalue", + "title": "Endpoint status" + }, + { + "assettypes": [ + "computer" + ], + "collapsible": true, + "commandendpoint": "/api/endpoints/{assetid}/commands", + "empty": "No monitored services reported.", + "endpoint": "/api/endpoints/asset/{assetid}/services", + "facets": { + "key": "statelabel", + "order": [ + "Running", + "Stopped", + "Paused", + "" + ] + }, + "filter": { + "equals": "service", + "key": "kind" + }, + "group": "serviceprocess", + "id": "endpoints-tracked-services", + "map": { + "action": "action", + "badge": { + "color": "statecolor", + "label": "statelabel" + }, + "title": "name" + }, + "permission": "endpoints.command", + "plugin": "endpoints", + "position": 12, + "render": "list", + "status": { + "key": "statecolor", + "levels": { + "green": "ok", + "red": "critical", + "yellow": "warning" + } + }, + "title": "Tracked Services" + }, + { + "assettypes": [ + "computer" + ], + "collapsible": true, + "commandendpoint": "/api/endpoints/{assetid}/commands", + "empty": "No monitored processes reported.", + "endpoint": "/api/endpoints/asset/{assetid}/services", + "facets": { + "key": "statelabel", + "order": [ + "Running", + "Stopped", + "Paused", + "" + ] + }, + "filter": { + "equals": "process", + "key": "kind" + }, + "group": "serviceprocess", + "id": "endpoints-tracked-processes", + "map": { + "action": "action", + "badge": { + "color": "statecolor", + "label": "statelabel" + }, + "title": "name" + }, + "permission": "endpoints.command", + "plugin": "endpoints", + "position": 13, + "render": "list", + "status": { + "key": "statecolor", + "levels": { + "green": "ok", + "red": "critical", + "yellow": "warning" + } + }, + "title": "Tracked Processes" + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7016,7 +9943,17 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "assetid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] } }, "/api/pluginui/asset-presentation": { @@ -7036,7 +9973,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assettype": "measuring_tool", + "icon": "ruler", + "label": "Measuring Tool", + "plugin": "measuringtools", + "route": "/measuringtools/by-asset/{assetid}" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7074,7 +10029,52 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assettype": "computer", + "edit_permission": "computers.manage", + "optional_tabs": [], + "plugin": "computers", + "subtype_color_field": "color", + "subtype_description_field": "description", + "subtype_endpoint": "/computers/types", + "subtype_id_field": "computertypeid", + "subtype_label_field": "computertype" + }, + { + "assettype": "machine", + "edit_permission": "machines.manage", + "optional_tabs": [], + "plugin": "machines", + "subtype_color_field": "color", + "subtype_description_field": "description", + "subtype_endpoint": "/machines/types", + "subtype_id_field": "machinetypeid", + "subtype_label_field": "machinetype" + }, + { + "assettype": "measuring_tool", + "edit_permission": "measuringtools.manage", + "optional_tabs": [], + "plugin": "measuringtools", + "subtype_color_field": "color", + "subtype_description_field": "description", + "subtype_endpoint": "/measuringtools/types", + "subtype_id_field": "measuringtooltypeid", + "subtype_label_field": "name" + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7112,7 +10112,45 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "category": "location", + "edit_permission": "admin", + "group": "other", + "optional_tabs": [], + "subtype_color_field": "color", + "subtype_description_field": "description", + "subtype_endpoint": "/locations/types", + "subtype_id_field": "locationtypeid", + "subtype_label_field": "locationtype", + "type_name": "Location Type", + "type_name_plural": "Location Types" + }, + { + "category": "notification", + "custom_component": "NotificationTypesTab", + "edit_permission": "admin", + "group": "other", + "optional_tabs": [], + "subtype_color_field": "typecolor", + "subtype_description_field": "typedescription", + "subtype_endpoint": "/notifications/types", + "subtype_id_field": "notificationtypeid", + "subtype_label_field": "typename", + "type_name": "Notification Type", + "type_name_plural": "Notification Types" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7150,7 +10188,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "endpoint": "/api/measuringtools/map-overlay", + "id": "calibration-due", + "label": "Calibration due", + "legend": true, + "plugin": "measuringtools", + "style": "badge" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7188,7 +10245,46 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "description": "Collection interval, share root for part-marker snapshots, staleness threshold and revision retention", + "group": "Machines", + "icon": "package", + "plugin": "backups", + "position": 21, + "title": "Backups", + "to": "/settings/backups" + }, + { + "description": "Download the collector script stamped with this site's URL and ranges", + "group": "Computers", + "icon": "download", + "plugin": "computers", + "position": 26, + "title": "Asset reporter", + "to": "/settings/collector" + }, + { + "description": "The shared agent key PCs use until they enroll, the site agent installer builder, and what the agent reports.", + "group": "Endpoints", + "icon": "key", + "plugin": "endpoints", + "position": 27, + "title": "Endpoints", + "to": "/settings/endpoints/agentkey" + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7226,7 +10322,43 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "reports": [ + { + "category": "inventory", + "description": "Machine count grouped by machine type", + "endpoint": "/api/reports/machines-by-type", + "id": "machines-by-type", + "name": "Machines by Type" + }, + { + "category": "inventory", + "description": "Asset count grouped by status", + "endpoint": "/api/reports/assets-by-status", + "id": "assets-by-status", + "name": "Assets by Status" + }, + { + "category": "usage", + "description": "Most clicked knowledge base articles", + "endpoint": "/api/reports/kb-popularity", + "id": "kb-popularity", + "name": "KB Popularity" + }, + "" + ], + "total": 13 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7264,7 +10396,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "data": { + "bylocation": [], + "bystatus": [], + "bytype": [] + }, + "generated": "2026-01-01T00:00:00.000000", + "report": "asset_inventory", + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7282,7 +10433,33 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] } }, "/api/reports/assets-by-status": { @@ -7302,7 +10479,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "data": [], + "generated": "2026-01-01T00:00:00.000000", + "report": "assets_by_status", + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7320,7 +10512,33 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "assettypeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/reports/email": { @@ -7340,7 +10558,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "reason": "notconfigured", + "sent": false + }, + "message": "Email is not configured (SMTP disabled or host unset).", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7367,6 +10599,21 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "columns": [ + { + "key": "vendor", + "label": "Vendor" + } + ], + "rows": [ + { + "vendor": "Dell" + } + ], + "subject": "Warranty Report", + "to": "" } } } @@ -7390,7 +10637,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "data": [], + "generated": "2026-01-01T00:00:00.000000", + "report": "kb_popularity", + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7408,7 +10670,26 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 20 + } + } + ] } }, "/api/reports/machines-by-type": { @@ -7428,7 +10709,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "data": [], + "generated": "2026-01-01T00:00:00.000000", + "report": "machines_by_type", + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7446,7 +10742,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/reports/pc-relationships": { @@ -7466,7 +10780,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "data": [ + { + "hostname": "", + "ip": "", + "machine_number": "4242", + "model": "", + "vendor": "" + } + ], + "generated": "2026-01-01T00:00:00.000000", + "report": "pc_relationships", + "total": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7484,7 +10821,17 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/reports/software-compliance": { @@ -7504,7 +10851,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "data": [], + "generated": "2026-01-01T00:00:00.000000", + "message": "No required applications defined", + "report": "software_compliance" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7522,7 +10884,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "appid", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/scripts": { @@ -7542,7 +10922,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7560,7 +10950,26 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -7578,7 +10987,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "captureoutput": false, + "createddate": "2026-01-01T00:00:00.000000Z", + "errormode": "default", + "filename": null, + "hasbody": false, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "runcontext": "system", + "scriptdescription": null, + "scriptid": 1, + "scriptname": "autologon", + "sha256": null, + "workingdirectory": "C:\\Program Files\\Sysinternals" + }, + "message": "Script created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7605,6 +11039,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "scriptname": "autologon", + "workingdirectory": "C:\\Program Files\\Sysinternals" } } } @@ -7628,7 +11066,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -7677,7 +11117,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -7726,7 +11168,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "captureoutput": true, + "createddate": "2026-01-01T00:00:00.000000Z", + "errormode": "default", + "filename": null, + "hasbody": false, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "runcontext": "system", + "scriptdescription": "now documented", + "scriptid": 1, + "scriptname": "keep-my-flag", + "sha256": null, + "workingdirectory": null + }, + "message": "Script updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7766,6 +11233,9 @@ "type": "object", "additionalProperties": true, "description": "path: script_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "scriptdescription": "now documented" } } } @@ -7789,7 +11259,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "bytes": 23, + "captureoutput": false, + "createddate": "2026-01-01T00:00:00.000000Z", + "errormode": "default", + "filename": "script-1.ps1", + "hasbody": true, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "runcontext": "system", + "scriptdescription": null, + "scriptid": 1, + "scriptname": "digest-check", + "sha256": "", + "uploadedfilename": "digest-check.ps1", + "workingdirectory": null + }, + "message": "Script body uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7852,7 +11349,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -7904,7 +11403,47 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "counts": { + "knowledgebase": 2 + }, + "degraded": [ + "Employee" + ], + "query": "zzkeyword", + "results": [ + { + "id": 1, + "linkurl": "u", + "relevance": 25.0, + "subtitle": "Livesearchapp", + "title": "Zzrunbook for the live one", + "type": "knowledgebase", + "url": "/knowledgebase/1" + }, + { + "id": 3, + "linkurl": "u", + "relevance": 25.0, + "subtitle": null, + "title": "Zzrunbook with no topic", + "type": "knowledgebase", + "url": "/knowledgebase/3" + } + ], + "total": 2, + "total_all": 2 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7922,7 +11461,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "q", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + } + ] } }, "/api/search/suggest": { @@ -7942,7 +11492,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "query": "keyecne", + "suggestion": "keyence" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7960,7 +11523,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "q", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + } + ] } }, "/api/settings": { @@ -7981,7 +11555,49 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "category": "auth", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "SAML Assertion Consumer Service URL", + "key": "saml_acs_url", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 111, + "value": "", + "valuetype": "string" + }, + { + "category": "auth", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "SAML group name that grants admin role", + "key": "saml_admin_group", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 114, + "value": "", + "valuetype": "string" + }, + { + "category": "auth", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Allow local username/password login when SAML is enabled", + "key": "saml_allow_local_login", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 112, + "value": true, + "valuetype": "boolean" + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -7993,7 +11609,17 @@ } } } - } + }, + "parameters": [ + { + "name": "category", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -8011,7 +11637,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8062,7 +11690,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "category": "plugin.endpoints", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Accept a one-line install bootstrap token in the ?t= query string as well as the X-Endpoint-Bootstrap-Token header. On (the default) keeps the pasted install commands and the Download .ps1 link workin...", + "key": "plugin.endpoints.bootstrapquerytoken", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 1, + "value": false, + "valuetype": "boolean" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8105,7 +11752,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "category": "plugin.endpoints", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Accept a one-line install bootstrap token in the ?t= query string as well as the X-Endpoint-Bootstrap-Token header. On (the default) keeps the pasted install commands and the Download .ps1 link workin...", + "key": "plugin.endpoints.bootstrapquerytoken", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "settingid": 1, + "value": false, + "valuetype": "boolean" + }, + "message": "Setting updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8145,6 +11812,9 @@ "type": "object", "additionalProperties": true, "description": "path: key (string); body: JSON (fields not yet documented)" + }, + "example": { + "value": "" } } } @@ -8168,7 +11838,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8218,7 +11890,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8256,7 +11930,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "tables": [ + { + "filename": "assetstatuses.csv", + "table": "assetstatuses" + }, + { + "filename": "assettypes.csv", + "table": "assettypes" + }, + { + "filename": "locationtypes.csv", + "table": "locationtypes" + }, + "" + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8294,7 +11994,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8345,7 +12047,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "batches": [ + { + "batchid": "", + "createdat": "2026-01-01 00:00:00.000000", + "createdby": "", + "kind": "winc-machine-adoption", + "rowcount": 1, + "status": "undone", + "undoneat": "2026-01-01 00:00:00.000000" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8383,7 +12107,46 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "batchid": "", + "blocking": false, + "committed": true, + "kind": "winc-machine-adoption", + "needscreate": { + "businessunit": { + "Large Parts": 1 + } + }, + "planhash": "", + "rowcount": 1, + "summary": { + "ambiguous_match": 0, + "businessunit_blank": 0, + "businessunit_needs-create": 1, + "businessunit_resolved": 0, + "businessunit_unresolved": 0, + "export_rows": 2, + "in_scope": 1, + "location_blank": 0, + "location_needs-create": 0, + "location_resolved": 1, + "location_unresolved": 0, + "non_workstation_rows": 1, + "skipped_no_existing_machine": 0 + }, + "uncreatable": {}, + "unresolved": {} + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8433,7 +12196,52 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "blocking": true, + "committed": false, + "kind": "winc-machine-adoption", + "needscreate": { + "businessunit": { + "Large Parts": 1 + }, + "location": { + "T6": 1 + } + }, + "planhash": "", + "rowcount": 1, + "summary": { + "ambiguous_match": 0, + "businessunit_blank": 0, + "businessunit_needs-create": 1, + "businessunit_resolved": 0, + "businessunit_unresolved": 0, + "export_rows": 1, + "in_scope": 1, + "location_blank": 0, + "location_needs-create": 1, + "location_resolved": 0, + "location_unresolved": 0, + "non_workstation_rows": 0, + "skipped_no_existing_machine": 0 + }, + "uncreatable": { + "location": { + "T6": 1 + } + }, + "unresolved": {} + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8483,7 +12291,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "batchid": "", + "conflicts": [ + { + "column": null, + "operation": "insert", + "reason": "still referenced by dashboarddefaults.businessunitid", + "table": "businessunits", + "targetid": 1 + } + ], + "reverted": 3 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8510,6 +12340,9 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "batchid": "" } } } @@ -8533,7 +12366,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "key": "site_favicon", + "value": "/api/settings/branding/logo-favicon.ico" + }, + "message": "Logo uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8579,7 +12426,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8625,7 +12474,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8671,7 +12522,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8717,7 +12570,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "created": 112 + }, + "message": "112 default settings created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8744,7 +12610,8 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" - } + }, + "example": {} } } } @@ -8767,7 +12634,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "error": "[Errno -2] Name or service not known", + "sent": false + }, + "message": "Test email failed: [Errno -2] Name or service not known", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8794,6 +12675,9 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "to": "" } } } @@ -8817,7 +12701,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8863,7 +12749,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8903,7 +12791,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "needsadmin": false + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -8935,7 +12835,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -8985,7 +12887,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -9035,7 +12939,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "count": 0, + "lastgoodat": null, + "requestid": "00000000", + "retention": { + "keepdaily": 5, + "keepmonthly": 6, + "keepweekly": 4 + }, + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9071,7 +12992,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -9121,7 +13044,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -9172,7 +13097,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -9235,7 +13162,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "queued": true, + "snapshotid": "wj-2026-09-06T120000Z" + }, + "message": "Schema upgrade queued.", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9285,7 +13226,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "backups": [], + "restores": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9323,7 +13277,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "backupsroot": "/backups", + "destinationkind": "local", + "destinationkinds": [ + "local", + "smb", + "aws" + ], + "fields": {}, + "isarmed": true, + "retention": { + "keepdaily": 5, + "keepmonthly": 6, + "keepweekly": 4 + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9359,7 +13338,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "backupsroot": "/backups", + "destinationkind": "local", + "destinationkinds": [ + "local", + "smb", + "aws" + ], + "fields": {}, + "isarmed": true, + "retention": { + "keepdaily": 5, + "keepmonthly": 6, + "keepweekly": 4 + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9386,7 +13390,8 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" - } + }, + "example": {} } } } @@ -9409,7 +13414,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "backup": null, + "restore": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9447,7 +13465,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": false, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "supportteamid": 1, + "teamname": "Retired", + "teamurl": null, + "webhookurl": null + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9465,7 +13504,26 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "teamname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -9483,7 +13541,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "supportteamid": 1, + "teamname": "Controls", + "teamurl": "https://servicenow.example/group/controls", + "webhookurl": null + }, + "message": "Support team created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9510,6 +13588,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "createddate": "2026-01-01 00:00:00", + "modifieddate": "2026-01-01T00:00:00", + "teamname": "Legacy" } } } @@ -9533,7 +13616,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Support team deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9582,7 +13675,47 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "contacts": [ + { + "contactid": 2, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "First", + "sortorder": 1, + "sso": "111", + "supportteamid": 1 + }, + { + "contactid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Second", + "sortorder": 2, + "sso": "222", + "supportteamid": 1 + } + ], + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "supportteamid": 1, + "teamname": "Controls", + "teamurl": null, + "webhookurl": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9631,7 +13764,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "contacts": [], + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "supportteamid": 1, + "teamname": "Controls Renamed", + "teamurl": "https://x.example", + "webhookurl": null + }, + "message": "Support team updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9671,6 +13824,10 @@ "type": "object", "additionalProperties": true, "description": "path: team_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "teamname": "Controls Renamed", + "teamurl": "https://x.example" } } } @@ -9694,7 +13851,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "contactid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Second", + "sortorder": 2, + "sso": "222", + "supportteamid": 1 + }, + "message": "Contact created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9734,6 +13911,11 @@ "type": "object", "additionalProperties": true, "description": "path: team_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "createddate": "2026-01-01 00:00:00", + "modifieddate": "2026-01-01T00:00:00", + "name": "LegacyOwner" } } } @@ -9757,7 +13939,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Contact deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9814,7 +14006,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "contactid": 2, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "First Updated", + "sortorder": 1, + "sso": "111", + "supportteamid": 1 + }, + "message": "Contact updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9862,6 +14074,9 @@ "type": "object", "additionalProperties": true, "description": "path: team_id (int), contact_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "name": "First Updated" } } } @@ -9885,7 +14100,46 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "createddate": "2026-01-01T00:00:00.000000Z", + "directpermissions": [], + "email": "", + "failedlogins": 0, + "firstname": "", + "isactive": true, + "islocked": false, + "lastlogindate": "2026-01-01T00:00:00Z", + "lastname": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "mustchangepassword": "", + "permissions": [ + "apitokens.create", + "applications.create", + "applications.delete", + "" + ], + "roles": [ + { + "color": null, + "roleid": 1, + "rolename": "admin" + } + ], + "userid": 1, + "username": "" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9921,7 +14175,48 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "directpermissions": [ + "endpoints.restart" + ], + "email": "", + "failedlogins": 0, + "firstname": "", + "isactive": true, + "islocked": false, + "lastlogindate": null, + "lastname": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "mustchangepassword": "", + "permissions": [ + "applications.view", + "assets.view", + "backups.download", + "" + ], + "roles": [ + { + "color": "#0DCAF0", + "roleid": 3, + "rolename": "technician" + } + ], + "userid": 2, + "username": "", + "warning": "User created but the welcome email could not be sent." + }, + "message": "User created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -9948,6 +14243,16 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "directpermissions": [ + "endpoints.runscript" + ], + "email": "", + "password": "", + "roles": [], + "sendwelcome": false, + "username": "" } } } @@ -9971,7 +14276,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "User deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10020,7 +14335,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "directpermissions": [], + "email": "", + "failedlogins": 0, + "firstname": "", + "isactive": true, + "islocked": false, + "lastlogindate": "2026-01-01T00:00:00Z", + "lastname": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "mustchangepassword": "", + "permissions": [], + "roles": [], + "userid": 1, + "username": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10069,7 +14410,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "directpermissions": [], + "email": "", + "failedlogins": 0, + "firstname": "", + "isactive": true, + "islocked": false, + "lastlogindate": null, + "lastname": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "mustchangepassword": "", + "permissions": [], + "roles": [], + "userid": 2, + "username": "" + }, + "message": "User updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10109,6 +14477,9 @@ "type": "object", "additionalProperties": true, "description": "path: userid (int); body: JSON (fields not yet documented)" + }, + "example": { + "password": "" } } } @@ -10132,7 +14503,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10170,7 +14543,45 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "color": null, + "description": "Administrator", + "grantable": null, + "isadmin": true, + "isguest": false, + "permissions": [], + "roleid": 1, + "rolename": "admin", + "usercount": 1 + }, + { + "color": "#6C757D", + "description": "Anyone who is not signed in. Holds nothing by default; grant it a permission to open that up to people with no account.", + "grantable": [ + "applications.view", + "assets.view", + "computers.view", + "" + ], + "isadmin": false, + "isguest": true, + "permissions": [], + "roleid": 2, + "rolename": "guest", + "usercount": 0 + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10206,7 +14617,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "color": "#ff8800", + "description": "colorful", + "permissions": [], + "roleid": 2, + "rolename": "painters" + }, + "message": "Role created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10233,6 +14661,12 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "color": "#ff8800", + "description": "colorful", + "permissions": [], + "rolename": "painters" } } } @@ -10256,7 +14690,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10305,7 +14741,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "color": "#6C757D", + "description": "Anyone who is not signed in. Holds nothing by default; grant it a permission to open that up to people with no account.", + "permissions": [ + "reports.view" + ], + "roleid": 2, + "rolename": "guest" + }, + "message": "Role updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10345,6 +14800,11 @@ "type": "object", "additionalProperties": true, "description": "path: roleid (int); body: JSON (fields not yet documented)" + }, + "example": { + "permissions": [ + "reports.view" + ] } } } @@ -10368,7 +14828,38 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "supportemail": "", + "supportphone": "", + "vendor": "Acme", + "vendorid": 1, + "website": null + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10386,7 +14877,59 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "vendor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -10404,7 +14947,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "supportemail": "", + "supportphone": "", + "vendor": "Unscoped Vendor", + "vendorid": 1, + "website": null + }, + "message": "Vendor created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10431,6 +14996,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "createddate": "2026-01-01 00:00:00", + "modifieddate": "2026-01-01T00:00:00", + "vendor": "LegacyVendor" } } } @@ -10454,7 +15024,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10503,7 +15075,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10552,7 +15126,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10615,7 +15191,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10645,6 +15223,14 @@ "schema": { "type": "integer" } + }, + { + "name": "kind", + "in": "query", + "required": false, + "schema": { + "type": "string" + } } ] } @@ -10666,7 +15252,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10696,6 +15284,14 @@ "schema": { "type": "integer" } + }, + { + "name": "kind", + "in": "query", + "required": false, + "schema": { + "type": "string" + } } ] } @@ -10717,7 +15313,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10755,7 +15361,51 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assettypes": [ + "machine" + ], + "displayname": "", + "formats": [ + { + "ext": ".reg", + "hint": "Restore with the Load... button in the NTLARS settings dialog.", + "id": "ntlars", + "label": "NTLARS Load... (.reg)", + "mimetype": "application/octet-stream" + }, + { + "ext": ".reg", + "hint": "Use when importing outside NTLARS on a 64-bit machine.", + "id": "wow6432node", + "label": "Direct reg import (.reg, WOW6432Node)", + "mimetype": "application/octet-stream" + } + ], + "key": "ntlars", + "storagebackend": "shopdb" + }, + { + "assettypes": [ + "machine" + ], + "displayname": "", + "formats": [], + "key": "partmarker", + "storagebackend": "share" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10793,7 +15443,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10844,7 +15496,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "againstid": 1, + "backuprevisionid": 2, + "changecount": 1, + "changes": [ + { + "after": "OKUMA", + "aftertype": "REG_SZ", + "before": "", + "beforetype": "REG_SZ", + "change": "changed", + "keypath": "General", + "valuename": "Cnc" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10874,6 +15551,14 @@ "schema": { "type": "integer" } + }, + { + "name": "against", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } } ] } @@ -10895,7 +15580,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -10925,6 +15612,14 @@ "schema": { "type": "integer" } + }, + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } } ] } @@ -10946,7 +15641,79 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "accessmethods": [], + "assetid": 1, + "assetnumber": "PC-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "computer", + "businessunitid": null, + "computer": { + "accessprotocolnames": [], + "assetid": 1, + "azuredevicecategory": null, + "azuredeviceid": null, + "azureobjectid": null, + "computerid": 1, + "computertypeid": 1, + "computertypename": "Standard", + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "isactive": true, + "lastboottime": null, + "lastreporteddate": null, + "loggedinuser": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "osid": null, + "vendorid": null + }, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -10964,7 +15731,149 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "assetnumber", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "businessunit_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "dir", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "asc" + } + }, + { + "name": "location_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "os_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "osid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "shopfloor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "hostname" + } + }, + { + "name": "type_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "typeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -10982,7 +15891,71 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "accessmethods": [], + "assetid": 1, + "assetnumber": "AUDIT-PC-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "computer", + "businessunitid": null, + "computer": { + "accessprotocolnames": [], + "assetid": 1, + "azuredevicecategory": null, + "azuredeviceid": null, + "azureobjectid": null, + "computerid": 1, + "computertypeid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "isactive": true, + "lastboottime": null, + "lastreporteddate": null, + "loggedinuser": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "osid": null, + "vendorid": null + }, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "message": "Computer created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -11009,6 +15982,12 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "assetnumber": "PC-IMPORT-1", + "createddate": "2026-01-01 00:00:00", + "hostname": "", + "modifieddate": "2026-01-01T00:00:00" } } } @@ -11032,7 +16011,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11081,7 +16062,71 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "accessmethods": [], + "assetid": 1, + "assetnumber": "PC-2001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "computer", + "businessunitid": null, + "communications": [], + "computer": { + "accessprotocolnames": [], + "assetid": 1, + "azuredevicecategory": null, + "azuredeviceid": null, + "azureobjectid": null, + "computerid": 1, + "computertypeid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "imageurl": "/api/models/images/model-1.png", + "isactive": true, + "lastboottime": null, + "lastreporteddate": null, + "loggedinuser": null, + "modelname": "IMG-MODEL-1", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "osid": null, + "vendorid": null + }, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -11130,7 +16175,83 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "accessmethods": [ + { + "id": 1, + "link": "rdp://auditpc1", + "name": "RDP", + "port": null, + "portoverride": null, + "protocolid": 1, + "scheme": "rdp" + } + ], + "assetid": 1, + "assetnumber": "AUDIT-PC-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "computer", + "businessunitid": null, + "computer": { + "accessprotocolnames": [ + "RDP" + ], + "assetid": 1, + "azuredevicecategory": null, + "azuredeviceid": null, + "azureobjectid": null, + "computerid": 1, + "computertypeid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "isactive": true, + "lastboottime": null, + "lastreporteddate": null, + "loggedinuser": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "osid": null, + "vendorid": null + }, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "message": "Computer updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -11170,6 +16291,10 @@ "type": "object", "additionalProperties": true, "description": "path: computer_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "gaugelabreference": "GL-2", + "maintenancereference": "MNT-2" } } } @@ -11193,7 +16318,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11242,7 +16369,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11305,7 +16434,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11364,7 +16495,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11427,7 +16560,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11478,7 +16613,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11529,7 +16666,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11580,7 +16719,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11618,7 +16759,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "computerid": 2, + "hostname": "", + "lastreported": "2026-01-01T00:00:00.000000Z", + "quietdays": 9 + }, + { + "computerid": 1, + "hostname": "", + "lastreported": "2026-01-01T00:00:00.000000Z", + "quietdays": 2 + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -11656,7 +16820,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assetid": 1, + "machinenumber": "2026", + "pccount": 2, + "pcs": "PCONE, PCTWO" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -11694,7 +16875,23 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "byos": [], + "bytype": [], + "nonshopfloor": 0, + "shopfloor": 0, + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -11732,7 +16929,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "computerid": 1, + "fqdn": "", + "hostname": "", + "serialnumber": "" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -11770,7 +16984,43 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "action": "service_start", + "description": "Start a Windows service by name on the endpoint.", + "kind": "command", + "label": "Start service", + "mayauthor": true, + "requiredpermission": null + }, + { + "action": "service_stop", + "description": "Stop a running Windows service by name on the endpoint.", + "kind": "command", + "label": "Stop service", + "mayauthor": true, + "requiredpermission": null + }, + { + "action": "service_status", + "description": "Report whether a named Windows service is running.", + "kind": "command", + "label": "Check service", + "mayauthor": true, + "requiredpermission": null + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -11808,7 +17058,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11844,7 +17096,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11894,7 +17148,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11943,7 +17199,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -11992,7 +17250,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12055,7 +17315,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12091,7 +17353,42 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "actions": [ + { + "action": "run_script", + "configurationpolicyactionid": 1, + "configurationpolicyid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "desiredstate": null, + "intervalminutes": null, + "isactive": true, + "mode": "gate", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "params": null, + "sortorder": 0 + } + ], + "configurationpolicyid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Legitimate", + "scopejson": null, + "source": "local" + }, + "message": "Configuration policy created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -12118,6 +17415,14 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "actions": [ + { + "action": "run_script" + } + ], + "name": "Legitimate" } } } @@ -12141,7 +17446,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12190,7 +17497,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12239,7 +17548,42 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "actions": [ + { + "action": "run_script", + "configurationpolicyactionid": 1, + "configurationpolicyid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "desiredstate": null, + "intervalminutes": null, + "isactive": true, + "mode": "gate", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "params": null, + "sortorder": 0 + } + ], + "configurationpolicyid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "clearer wording", + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "New Name", + "scopejson": null, + "source": "local" + }, + "message": "Configuration policy updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -12279,6 +17623,10 @@ "type": "object", "additionalProperties": true, "description": "path: policy_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "description": "clearer wording", + "name": "New Name" } } } @@ -12302,7 +17650,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12353,7 +17703,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -12371,7 +17731,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + } + ] }, "post": { "tags": [ @@ -12389,7 +17760,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12439,7 +17812,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12488,7 +17863,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12549,7 +17926,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12612,7 +17991,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -12630,7 +18027,51 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -12648,7 +18089,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12698,7 +18141,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12747,7 +18192,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12796,7 +18243,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -12859,7 +18308,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "First_Name": "Test", + "Last_Name": "Person", + "Picture": null, + "Role": null, + "SSO": 210000001, + "Team": null, + "photofilename": null, + "photourl": null + }, + "message": "Employee photo removed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -12908,7 +18377,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "First_Name": "Test", + "Last_Name": "Person", + "Picture": null, + "Role": null, + "SSO": 210000001, + "Team": null, + "photofilename": "photo-210000001.jpg", + "photourl": "/api/employees/photo/photo-210000001.jpg" + }, + "message": "Employee photo uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -12971,7 +18460,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13007,7 +18498,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13057,7 +18550,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13106,7 +18601,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13169,7 +18666,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13219,7 +18718,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13237,7 +18738,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "sso", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + } + ] } }, "/api/employees/lookup/{sso}": { @@ -13257,7 +18769,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "First_Name": "Test", + "Last_Name": "Person", + "Picture": null, + "Role": null, + "SSO": 210000001, + "Team": null, + "photofilename": "photo-210000001.png", + "photourl": "/api/employees/photo/photo-210000001.png" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13304,7 +18835,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13350,7 +18883,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "error": "No name found in the directory or in a user account", + "mode": "selfhosted", + "name": null, + "photourl": null, + "source": null, + "sso": "999999" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13401,7 +18951,38 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "First_Name": "Dana", + "Last_Name": "Reyes", + "Picture": null, + "Role": null, + "SSO": 990005, + "Team": null, + "photofilename": null, + "photourl": null + }, + { + "First_Name": "Sam", + "Last_Name": "Reyes", + "Picture": null, + "Role": null, + "SSO": 990006, + "Team": null, + "photofilename": null, + "photourl": null + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13419,7 +19000,27 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 10 + } + }, + { + "name": "q", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + } + ] } }, "/api/endpoints": { @@ -13439,7 +19040,58 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "agentversion": null, + "alias": "Bay 3 Controller", + "assetid": 1, + "assetnumber": "fleetbox", + "computerid": 1, + "computertype": null, + "computertypeid": null, + "cpupercent": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "credentialstate": "", + "domain": null, + "endpointstateid": 1, + "health": { + "label": "no agent", + "level": "unknown" + }, + "hostname": "", + "idleseconds": null, + "lastboottime": null, + "lastreportedat": null, + "loggedinuser": null, + "machines": [], + "memorypercent": null, + "mtconnectcheckedat": null, + "mtconnectrunning": null, + "pendingreboot": null, + "status": "never", + "trayversion": null, + "uptimedisplay": null, + "uptimeseconds": null + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13457,7 +19109,90 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "computertypeid", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "credentialstate", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/endpoints/{asset_id}": { @@ -13477,7 +19212,52 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "actionminimums": { + "collect_log": "1.16.0" + }, + "agentcurrent": "1.6.3", + "agentversion": "1.20.0", + "assetid": 2, + "cpupercent": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "credential": { + "credentialprefix": "", + "enrolledvia": "auto", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": "2026-01-01T00:00:00.000000Z", + "reenrollblocked": true, + "reenrollblockedreason": "rollback", + "revokedat": "2026-01-01T00:00:00.000000Z", + "state": "reenrollblocked", + "statelabel": "Re-enroll blocked" + }, + "domain": null, + "endpointstateid": 2, + "hostname": "", + "idleseconds": null, + "lastboottime": null, + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "loggedinuser": null, + "memorypercent": null, + "mtconnectcheckedat": null, + "mtconnectrunning": null, + "pendingreboot": null, + "status": "reporting", + "trayversion": null, + "uptimedisplay": null, + "uptimeseconds": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13528,7 +19308,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "action": "run_script", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "endpointcommandid": 1, + "requestedby": "", + "resultmessage": null, + "status": "pending", + "target": "script:1", + "targetkind": "script" + }, + "message": "Command queued", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13568,6 +19371,10 @@ "type": "object", "additionalProperties": true, "description": "path: asset_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "action": "run_script", + "target": "script:1" } } } @@ -13591,7 +19398,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13640,7 +19449,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "action": "collect_log", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00.000000Z", + "endpointcommandid": 1, + "requestedby": "", + "resultmessage": null, + "status": "pending", + "target": "C:\\logs\\app.log", + "targetkind": "logpath" + }, + "message": "Command queued", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13680,6 +19512,12 @@ "type": "object", "additionalProperties": true, "description": "path: asset_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "action": "service_status", + "overridereason": "line down, need status", + "policyoverride": true, + "target": "spooler" } } } @@ -13703,7 +19541,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -13733,6 +19573,39 @@ "schema": { "type": "integer" } + }, + { + "name": "eventid", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } } ] } @@ -13754,7 +19627,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "action": "service_start", + "held": false + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13805,7 +19693,16 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13854,7 +19751,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "endpointlockid": 1, + "lockedat": "2026-01-01T00:00:00.000000Z", + "lockedbyuserid": 1, + "lockedbyusername": "", + "reason": "visible to all", + "releasedat": null, + "releasedbyusername": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13903,7 +19819,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "endpointlockid": 1, + "lockedat": "2026-01-01T00:00:00.000000Z", + "lockedbyuserid": 1, + "lockedbyusername": "", + "reason": "locked but still reconciled", + "releasedat": null, + "releasedbyusername": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -13943,6 +19878,9 @@ "type": "object", "additionalProperties": true, "description": "path: asset_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "reason": "locked but still reconciled" } } } @@ -13966,7 +19904,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14017,7 +19957,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "action": "service_stop", + "createdbyusername": "", + "expiresat": "2026-01-01T00:00:00.000000", + "reason": "vendor on site" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -14066,7 +20023,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "action": "service_stop", + "createdbyusername": "", + "expiresat": "2026-01-01T00:00:00.000000", + "reason": "stripping the enclosure" + }, + { + "action": "service_start", + "createdbyusername": "", + "expiresat": "2026-01-01T00:00:00.000000", + "reason": "stripping the enclosure" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -14106,6 +20086,14 @@ "type": "object", "additionalProperties": true, "description": "path: asset_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "actions": [ + "service_start", + "service_stop" + ], + "minutes": 60, + "reason": "stripping the enclosure" } } } @@ -14129,7 +20117,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -14188,7 +20186,64 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "action": "run_script", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00Z", + "endpointcommandid": 6, + "requestedby": "", + "resultdetail": null, + "resultmessage": null, + "scriptname": "test-open-notepad", + "status": "succeeded", + "target": "script:1", + "targetkind": null + }, + { + "action": "run_script", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00Z", + "endpointcommandid": 5, + "requestedby": "", + "resultdetail": null, + "resultmessage": null, + "scriptname": "test-open-notepad", + "status": "succeeded", + "target": "script:1", + "targetkind": null + }, + { + "action": "run_script", + "assetid": 1, + "claimedat": null, + "completedat": null, + "createdat": "2026-01-01T00:00:00Z", + "endpointcommandid": 4, + "requestedby": "", + "resultdetail": null, + "resultmessage": null, + "scriptname": "test-open-notepad", + "status": "succeeded", + "target": "script:1", + "targetkind": null + }, + "" + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -14218,6 +20273,15 @@ "schema": { "type": "integer" } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 5 + } } ] } @@ -14239,7 +20303,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14289,7 +20355,23 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "envkeyfallback": true, + "key": null, + "provisioned": false, + "revoked": 0 + }, + "message": "Endpoint agent key revoked", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -14325,7 +20407,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14363,7 +20447,39 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "envkeyfallback": false, + "key": { + "createddate": "2026-01-01T00:00:00.000000Z", + "displayprefix": "", + "expiresat": null, + "isactive": true, + "isexpired": false, + "lastusedat": null, + "name": "Endpoint agent key", + "resourcescopes": null, + "scopes": [ + "collector.ingest.endpoints" + ], + "tokenid": 1, + "tokenprefix": "", + "userid": 1 + }, + "provisioned": true, + "secret": "", + "warning": "Save this key now. It will not be shown again. Configure it as the agent X-API-Key." + }, + "message": "Endpoint agent key generated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -14390,7 +20506,8 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" - } + }, + "example": {} } } } @@ -14413,7 +20530,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "message": "Scheduled maintenance at 3:30 PM", + "notificationId": 1, + "notificationid": 1, + "timeout": 0, + "title": "Scheduled maintenance at 3:30 PM", + "type": "Fleet Alert", + "typeColor": "#ffc107", + "typecolor": "#ffc107" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -14431,7 +20569,17 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "hostname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/endpoints/alerts/{notification_id}/acknowledge": { @@ -14451,7 +20599,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "acknowledged": true + }, + "message": "Alert already acknowledged", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -14491,6 +20652,10 @@ "type": "object", "additionalProperties": true, "description": "path: notification_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "assetid": 1, + "hostname": "" } } } @@ -14514,7 +20679,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14565,7 +20732,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14616,7 +20785,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14676,7 +20847,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14727,7 +20900,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14778,7 +20953,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14829,7 +21006,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14880,7 +21059,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14931,7 +21112,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -14982,7 +21165,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15033,7 +21218,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15084,7 +21271,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15135,7 +21324,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15186,7 +21377,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "action": { + "running": false, + "start": "process_start", + "status": "process_status", + "stop": "process_stop", + "target": "dncMain.exe", + "targetkind": "process" + }, + "drift": true, + "kind": "process", + "name": "eDNC", + "statecolor": "gray", + "statelabel": "Unknown" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15237,7 +21454,51 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "agentbehind": false, + "agentcurrent": "1.6.3", + "agentversion": "1.20.0", + "credential": { + "credentialprefix": "", + "enrolledvia": "auto", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": "2026-01-01T00:00:00.000000Z", + "reenrollblocked": true, + "reenrollblockedreason": "rollback", + "revokedat": "2026-01-01T00:00:00.000000Z", + "state": "reenrollblocked", + "statelabel": "Re-enroll blocked" + }, + "fields": [ + { + "label": "Agent", + "mono": true, + "value": "1.20.0" + }, + { + "format": "datetime", + "label": "Last reported", + "mono": false, + "value": "2026-01-01T00:00:00.000000Z" + }, + { + "label": "Credential", + "mono": false, + "value": "Re-enroll blocked" + }, + "" + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15288,7 +21549,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15339,7 +21602,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15390,7 +21655,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15441,7 +21708,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "action": "created", + "assetid": 1, + "identityvalue": "BAY-01", + "status": "ok", + "warnings": [] + }, + "message": "endpoints collector created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15468,6 +21752,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "agentversion": "1.20.0", + "hostname": "" } } } @@ -15491,7 +21779,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "action": "mtconnect_status", + "assetid": 1, + "claimedat": null, + "completedat": "2026-01-01T00:00:00.000000Z", + "createdat": "2026-01-01T00:00:00.000000Z", + "endpointcommandid": 1, + "requestedby": "", + "resultmessage": null, + "status": "succeeded", + "target": null, + "targetkind": null + }, + "message": "Result recorded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15521,6 +21832,14 @@ "schema": { "type": "integer" } + }, + { + "name": "hostname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } } ], "requestBody": { @@ -15531,6 +21850,9 @@ "type": "object", "additionalProperties": true, "description": "path: command_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "succeeded": true } } } @@ -15554,7 +21876,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "action": "mtconnect_status", + "endpointcommandid": 1, + "target": null, + "targetkind": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15572,7 +21909,17 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "hostname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/endpoints/dashboard/enrollmentpending": { @@ -15592,7 +21939,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "pendingcount": 2, + "summary": "2 PCs waiting for enrollment approval" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15630,7 +21992,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15668,7 +22032,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assetid": 2, + "blockeddays": 9, + "computerid": 2, + "hostname": "", + "reason": "rollback" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15706,7 +22088,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15744,7 +22128,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -15778,7 +22164,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "credential": "", + "status": "enrolled" + }, + "message": "Endpoint enrolled", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15799,6 +22200,13 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "agentversion": "1.20.0", + "deviceid": null, + "enrollnonce": "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", + "hostname": "", + "serialnumber": "" } } } @@ -15822,7 +22230,108 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "computers": [ + { + "assetid": 1, + "credentialprefix": "", + "enrolledvia": "auto", + "hostname": "", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "reenrollblocked": false, + "reenrollblockedreason": null, + "serialnumber": "", + "state": "enrolled" + }, + { + "assetid": 2, + "credentialprefix": "", + "enrolledvia": null, + "hostname": "", + "issuedat": null, + "lastusedat": null, + "reenrollblocked": false, + "reenrollblockedreason": null, + "serialnumber": "", + "state": "notenrolled" + }, + { + "assetid": 3, + "credentialprefix": "", + "enrolledvia": null, + "hostname": "", + "issuedat": null, + "lastusedat": null, + "reenrollblocked": false, + "reenrollblockedreason": null, + "serialnumber": "", + "state": "pending" + } + ], + "counts": { + "enrolled": 1, + "notenrolled": 1, + "pending": 1, + "pendingcomputers": 1 + }, + "requests": [ + { + "agentversion": "1.20.0", + "decidedat": null, + "decidedby": null, + "deviceid": null, + "hostname": "", + "lastseenat": "2026-01-01T00:00:00.000000Z", + "matchedassetid": 3, + "reason": "no serial on record", + "requestedat": "2026-01-01T00:00:00.000000Z", + "requestid": "00000000", + "serialnumber": "", + "sourceip": "127.0.0.1", + "status": "pending" + }, + { + "agentversion": "1.20.0", + "decidedat": null, + "decidedby": null, + "deviceid": null, + "hostname": "", + "lastseenat": "2026-01-01T00:00:00.000000Z", + "matchedassetid": 1, + "reason": null, + "requestedat": "2026-01-01T00:00:00.000000Z", + "requestid": "00000000", + "serialnumber": "", + "sourceip": "127.0.0.1", + "status": "issued" + } + ], + "settings": { + "autoenroll": true, + "maxpendingenrollments": 500, + "revokeddeniessharedkey": false, + "sharedkeyallowed": true + } + }, + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 3, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15840,7 +22349,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "state", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/endpoints/enrollment/assets/{assetid}/allow-reenroll": { @@ -15860,7 +22387,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "credentialid": 1, + "credentialprefix": "", + "enrolledvia": "auto", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "reenrollblocked": false, + "reenrollblockedreason": null, + "revokedat": "2026-01-01T00:00:00.000000Z", + "revokedby": "testadmin" + }, + "message": "Re-enrollment allowed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15923,7 +22472,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "credentialid": 1, + "credentialprefix": "", + "enrolledvia": "auto", + "issuedat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "reenrollblocked": true, + "reenrollblockedreason": "rollback", + "revokedat": "2026-01-01T00:00:00.000000Z", + "revokedby": "testadmin" + }, + "message": "Endpoint credential revoked", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -15963,6 +22534,10 @@ "type": "object", "additionalProperties": true, "description": "path: assetid (int); body: JSON (fields not yet documented)" + }, + "example": { + "blockreenroll": true, + "reason": "rollback" } } } @@ -15986,7 +22561,85 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "computers": [ + { + "agentversion": "1.19.0", + "assetid": 2, + "blockers": [], + "hostname": "", + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "state": "ready" + }, + { + "agentversion": "1.19.0", + "assetid": 3, + "blockers": [], + "hostname": "", + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "state": "ready" + }, + { + "agentversion": "1.20.0", + "assetid": 1, + "blockers": [ + "awaiting enrollment" + ], + "hostname": "", + "lastreportedat": "2026-01-01T00:00:00.000000Z", + "state": "blocked" + } + ], + "counts": { + "blocked": 1, + "enrolled": 0, + "notreporting": 0, + "pending": 0, + "ready": 2, + "upgrading": 0 + }, + "target": "1.20.0", + "waves": [ + { + "createdat": "2026-01-01T00:00:00Z", + "createdby": "", + "done": false, + "enrolled": 0, + "failed": 1, + "queued": 3, + "size": 3, + "waveid": 1 + }, + { + "createdat": "2026-01-01T00:00:00Z", + "createdby": "", + "done": false, + "enrolled": 0, + "failed": 0, + "queued": 2, + "size": 2, + "waveid": 2 + } + ] + }, + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 3, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16004,7 +22657,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "state", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/endpoints/enrollment/migration/wave": { @@ -16024,7 +22695,38 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "queued": [ + 1 + ], + "retried": [], + "skipped": [ + { + "assetid": 2, + "reason": "offline" + }, + { + "assetid": 3, + "reason": "notreporting" + }, + { + "assetid": 999999, + "reason": "not a computer" + } + ], + "waveid": 1 + }, + "message": "1 PC(s) queued", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16051,6 +22753,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "action": "run_script", + "target": "script:1" } } } @@ -16074,7 +22780,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "agentversion": "1.20.0", + "decidedat": "2026-01-01T00:00:00.000000Z", + "decidedby": "testadmin", + "deviceid": null, + "hostname": "", + "hostnameresult": "", + "lastseenat": "2026-01-01T00:00:00.000000Z", + "matchedassetid": 1, + "reason": null, + "requestedat": "2026-01-01T00:00:00.000000Z", + "requestid": "00000000", + "serialnumber": "", + "sourceip": "127.0.0.1", + "status": "approved" + }, + "message": "Enroll request approved; that computer was renamed to the hostname the PC reports", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16114,6 +22846,10 @@ "type": "object", "additionalProperties": true, "description": "path: requestid (int); body: JSON (fields not yet documented)" + }, + "example": { + "assetid": 1, + "sethostname": "" } } } @@ -16137,7 +22873,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "agentversion": "1.20.0", + "decidedat": "2026-01-01T00:00:00.000000Z", + "decidedby": "testadmin", + "deviceid": null, + "hostname": "", + "lastseenat": "2026-01-01T00:00:00.000000Z", + "matchedassetid": 1, + "reason": "awaiting approval", + "requestedat": "2026-01-01T00:00:00.000000Z", + "requestid": "00000000", + "serialnumber": "", + "sourceip": "127.0.0.1", + "status": "rejected" + }, + "message": "Enroll request rejected", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16200,7 +22961,23 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "autoenroll": true, + "maxpendingenrollments": 500, + "revokeddeniessharedkey": false, + "sharedkeyallowed": false + }, + "message": "Enrollment settings saved", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16227,6 +23004,9 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "revokeddeniessharedkey": true } } } @@ -16250,7 +23030,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16301,7 +23083,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16352,7 +23136,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16388,7 +23174,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16438,7 +23226,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16487,7 +23277,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createdat": "2026-01-01T00:00:00.000000Z", + "datacollectorpath": null, + "displayname": "", + "endpointmonitorid": 1, + "isactive": false, + "kind": "process", + "launchpath": "C:\\Program Files\\Dnc\\bin\\DncMain.exe", + "logcollectorpath": null, + "processname": "UDC", + "servicename": null, + "source": "shipped" + }, + "message": "Monitor updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16527,6 +23340,9 @@ "type": "object", "additionalProperties": true, "description": "path: monitor_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "launchpath": "D:\\Dnc\\bin\\DncMain.exe" } } } @@ -16550,7 +23366,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16568,7 +23386,17 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "pctype", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/endpoints/monitors/resolved": { @@ -16588,7 +23416,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "processes": [ + { + "app": "Edge", + "launchpath": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", + "name": "msedge.exe" + } + ], + "services": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16606,7 +23453,17 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "hostname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/endpoints/operatorreports": { @@ -16626,7 +23483,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "createdat": "2026-01-01T00:00:00.000000Z", + "details": "the CMM app will not start", + "hasimage": true, + "imagebytesize": 70, + "imagemimetype": "image/png", + "operatorreportid": 1, + "reason": "Other (free text)", + "reportedhostname": "" + }, + "message": "Operator report received", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16676,7 +23554,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16727,7 +23607,42 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "reports": [ + { + "assetid": 1, + "createdat": "2026-01-01T00:00:00.000000Z", + "details": "second", + "hasimage": false, + "imagebytesize": null, + "imagemimetype": null, + "operatorreportid": 2, + "reason": "Other (free text)", + "reportedhostname": "" + }, + { + "assetid": 1, + "createdat": "2026-01-01T00:00:00.000000Z", + "details": "first", + "hasimage": false, + "imagebytesize": null, + "imagemimetype": null, + "operatorreportid": 1, + "reason": "Other (free text)", + "reportedhostname": "" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16778,7 +23693,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16829,7 +23746,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "expires_in_days": 29, + "is_self_signed": true, + "issuer": "CN = pin.example.test", + "not_after": "Oct 18 18:57:47 2026 GMT", + "not_before": "Sep 17 18:57:47 2026 GMT", + "san_list": [], + "sha1thumbprint": "", + "spkisha256": "", + "subject_cn": "pin.example.test", + "thumbprint": "99:F1:E1:1D:5A:66:EE:44:8C:CA:5C:D8:BF:EA:C3:F3:8F:82:40:D3:5E:C9:4D:F0:AC:0B:3C:AD:80:D7:C1:DF" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16867,7 +23805,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -16905,7 +23845,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "message": "Certificate generated successfully. Nginx is restarting." + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16932,6 +23884,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "cn": "shopdb.example.test", + "days": 30, + "san": "" } } } @@ -16955,7 +23912,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "configured": true, + "error": "Could not read the certificate from shopdb.example.test:443 (Connection refused)", + "matchesfile": false, + "presentedsha1thumbprint": null, + "presentedspkisha256": null, + "url": "https://shopdb.example.test" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -16993,7 +23967,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "message": "Certificate uploaded successfully. Nginx is restarting." + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17043,7 +24029,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "agentcurrent": null, + "agentlegacy": null, + "agentstaged": false, + "agentversions": [], + "certavailable": true, + "serverpin": "", + "sharedkeyallowed": false, + "traycurrent": null, + "traylegacy": null, + "traystaged": false, + "trayversions": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17081,7 +24089,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -17130,7 +24140,51 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "binary": "agent", + "current": "", + "registration": { + "agentversion": "", + "appid": 1, + "appname": "ShopDB Endpoint Agent", + "contents": { + "agent": { + "filename": "shopdbagent.exe", + "sha256": "", + "version": "" + } + }, + "created": false, + "installpath": "/api/applications/package/1/shopdb-endpoint-agent.zip", + "ok": true, + "sha256": "", + "size": 135 + }, + "versions": [ + { + "iscurrent": true, + "size": 130, + "uploadedat": "2026-01-01T00:00:00.000000Z", + "version": "" + }, + { + "iscurrent": false, + "size": 130, + "uploadedat": "2026-01-01T00:00:00.000000Z", + "version": "" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17193,7 +24247,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -17256,7 +24312,51 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "binary": "agent", + "current": "", + "registration": { + "agentversion": "", + "appid": 1, + "appname": "ShopDB Endpoint Agent", + "contents": { + "agent": { + "filename": "shopdbagent.exe", + "sha256": "", + "version": "" + } + }, + "created": false, + "installpath": "/api/applications/package/1/shopdb-endpoint-agent.zip", + "ok": true, + "sha256": "", + "size": 135 + }, + "versions": [ + { + "iscurrent": false, + "size": 258, + "uploadedat": "2026-01-01T00:00:00.000000Z", + "version": "" + }, + { + "iscurrent": true, + "size": 258, + "uploadedat": "2026-01-01T00:00:00.000000Z", + "version": "" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17296,6 +24396,9 @@ "type": "object", "additionalProperties": true, "description": "path: binkey (string); body: JSON (fields not yet documented)" + }, + "example": { + "version": "" } } } @@ -17319,7 +24422,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -17382,7 +24487,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -17420,7 +24527,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -17458,7 +24567,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "tokens": [ + { + "createdat": "2026-01-01T00:00:00.000000Z", + "createdby": "", + "expiresat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "lastusedip": null, + "maxuses": 25, + "remaining": 25, + "revokedat": null, + "state": "active", + "tokenid": 1, + "tokenprefix": "", + "usecount": 0 + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17494,7 +24630,36 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "command": "powershell -ExecutionPolicy Bypass -c \"try { New-Item -ItemType Directory -Force -Path 'C:\\Program Files\\ShopDB\\bootstrap' | Out-Null; icacls 'C:\\Program Files\\ShopDB\\bootstrap' /inheritance:r /grant ...", + "scripturl": "https://shopdb.test/shopdb/api/endpoints/siteagent/bootstrap.ps1?t=&via=download", + "secret": "", + "token": { + "createdat": "2026-01-01T00:00:00.000000Z", + "createdby": "", + "expiresat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "lastusedip": null, + "maxuses": 500, + "remaining": 500, + "revokedat": null, + "state": "active", + "tokenid": 1, + "tokenprefix": "", + "usecount": 0 + } + }, + "message": "Bootstrap token created. The command is shown once.", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17521,6 +24686,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "hours": 6, + "maxuses": 3 } } } @@ -17544,7 +24713,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "token": { + "createdat": "2026-01-01T00:00:00.000000Z", + "createdby": "", + "expiresat": "2026-01-01T00:00:00.000000Z", + "lastusedat": null, + "lastusedip": null, + "maxuses": 25, + "remaining": 25, + "revokedat": "2026-01-01T00:00:00.000000Z", + "state": "revoked", + "tokenid": 1, + "tokenprefix": "", + "usecount": 0 + } + }, + "message": "Bootstrap token revoked", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17607,7 +24802,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -17634,6 +24831,13 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "baseurl": "https://shopdb.test", + "bundlecert": true, + "cadenceseconds": 900, + "collectorkey": "", + "nextserverpin": "" } } } @@ -17657,7 +24861,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "appid": 1, + "appname": "eDNC (tracked)" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17695,7 +24914,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "allowedcidrs": "", + "shareroot": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17731,7 +24963,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "shareroot": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17758,6 +25002,9 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "shareroot": "" } } } @@ -17781,7 +25028,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "computerid": null, + "entryname": "Install OpenText", + "exitcode": 1603, + "hostname": "", + "message": "Fatal error during installation", + "receivedat": "2026-01-01T00:00:00Z", + "scopename": "gea-shopfloor-cmm" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17819,7 +25086,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "deleted": 2 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17868,7 +25147,42 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "InUseCheck": { + "Behavior": "CloseAndReopen", + "Processes": [ + { + "ExePath": "C:\\PCDLRN.exe", + "GracefulCloseTimeoutSec": 15, + "Name": "PCDLRN" + } + ] + }, + "Installer": "apps/pcdmis.msi", + "LogFile": "C:\\Logs\\pcdmis.log", + "Name": "PC-DMIS", + "PCTypesStrict": true, + "PreEnrollment": true, + "Type": "MSI", + "appid": null, + "appname": null, + "entryid": 1, + "haspayload": false, + "payloadref": null, + "payloadsha256": null, + "payloadsource": "smb", + "sortorder": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -17908,6 +25222,24 @@ "type": "object", "additionalProperties": true, "description": "path: entryid (int); body: JSON (fields not yet documented)" + }, + "example": { + "InUseCheck": { + "Behavior": "CloseAndReopen", + "Processes": [ + { + "ExePath": "C:\\PCDLRN.exe", + "GracefulCloseTimeoutSec": 15, + "Name": "PCDLRN" + } + ] + }, + "Installer": "apps/pcdmis.msi", + "LogFile": "C:\\Logs\\pcdmis.log", + "Name": "PC-DMIS", + "PCTypesStrict": true, + "PreEnrollment": true, + "Type": "MSI" } } } @@ -17931,7 +25263,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -17980,7 +25314,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "Name": "eDNC install", + "PayloadRef": "config.reg", + "PayloadSha256": "", + "PayloadSource": "inline", + "Script": "scripts/x.ps1", + "Type": "PS1", + "appid": null, + "appname": null, + "entryid": 1, + "haspayload": true, + "payloadref": "config.reg", + "payloadsha256": "", + "payloadsource": "inline", + "sortorder": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18040,10 +25399,32 @@ ], "responses": { "200": { - "description": "Success. Body is the success_response envelope: {status, data, meta}.", + "description": "Success. This route does NOT return the standard envelope; the example is a transcript of a real response.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "example": { + "Version": "2.6", + "Applications": [ + { + "Name": "Alpha", + "Type": "MSI", + "Installer": "apps/alpha.msi", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\Alpha" + }, + { + "Name": "Beta", + "Type": "PS1", + "Script": "scripts/beta.ps1", + "DetectionMethod": "Always" + }, + { + "Name": "Gamma", + "Type": "PS1", + "Script": "scripts/gamma.ps1" + } + ] + } } } }, @@ -18061,7 +25442,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "pctype", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "phase", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/geenforce/payload/{sha256}": { @@ -18081,7 +25480,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -18132,7 +25533,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "reportid": 1, + "status": "selfhealed" + }, + "message": "recorded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18159,6 +25574,42 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "appliedversion": 1, + "counts": { + "failed": 1, + "filtered": 0, + "installed": 2, + "skipped": 1 + }, + "enforcerversion": "2.6", + "hostname": "", + "phase": "runtime", + "results": [ + { + "action": "installed", + "exitcode": 0, + "message": "rule re-added", + "name": "VNC firewall rule", + "selfhealed": true + }, + { + "action": "skipped", + "exitcode": 0, + "message": "", + "name": "PC-DMIS 2023.1", + "selfhealed": false + }, + { + "action": "installed", + "exitcode": 0, + "name": "eDNC config", + "selfhealed": true + }, + "" + ], + "scopename": "gea-shopfloor-cmm" } } } @@ -18182,7 +25633,55 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "appliedversion": null, + "assetnumber": "WJBAK10", + "backupcollectedat": "2026-01-01T00:00:00.000000Z", + "backupkind": "partmarker", + "backuplastseen": "2026-01-01T00:00:00.000000Z", + "backupok": false, + "backupstaleafterdays": 3, + "computerid": 1, + "displayrole": null, + "enforcerversion": null, + "failed": 0, + "filtered": 0, + "hostname": "", + "installed": 0, + "isstale": false, + "lastcheckin": null, + "latestversion": 1, + "levelid": null, + "location": null, + "machineassetid": null, + "machinenumber": null, + "machinepluginid": null, + "mapx": null, + "mapy": null, + "phase": "runtime", + "receivedat": "2026-01-01T00:00:00.000000Z", + "receivedlatest": false, + "reportid": 1, + "scopename": "gea-shopfloor-cmm", + "skipped": 0, + "staleafterminutes": 30, + "status": "ok", + "toolassetid": null, + "toolassetnumber": null, + "toolpluginid": null + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18200,7 +25699,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "hostname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "scopename", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/geenforce/reports/{reportid}": { @@ -18220,7 +25737,50 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appliedversion": 1, + "hostname": "", + "latestversion": 1, + "phase": "runtime", + "receivedlatest": true, + "reportid": 1, + "results": [ + { + "action": "installed", + "entryname": "VNC firewall rule", + "exitcode": 0, + "message": "rule re-added", + "selfhealed": true + }, + { + "action": "skipped", + "entryname": "PC-DMIS 2023.1", + "exitcode": 0, + "message": "", + "selfhealed": false + }, + { + "action": "installed", + "entryname": "eDNC config", + "exitcode": 0, + "message": null, + "selfhealed": true + }, + "" + ], + "scopename": "gea-shopfloor-cmm", + "status": "failed" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18271,7 +25831,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "computertypeid": null, + "entrycount": 2, + "iscommon": false, + "manifestversion": "2.6", + "measuringtooltypeid": null, + "minlibversion": null, + "phase": "runtime", + "publishedversion": 1, + "scopeid": 1, + "scopename": "gea-shopfloor-cmm" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18307,7 +25890,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "computertypeid": null, + "description": "test scope", + "entrycount": 0, + "iscommon": false, + "manifestversion": "1.0", + "measuringtooltypeid": null, + "phase": "runtime", + "publishedversion": null, + "scopeid": 1, + "scopename": "gea-shopfloor-collections" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18334,6 +25938,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "description": "test scope", + "phase": "runtime", + "scopename": "gea-shopfloor-collections" } } } @@ -18357,7 +25966,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "deleted": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18406,7 +26027,59 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "computertypeid": null, + "description": "test scope", + "entries": [ + { + "Name": "Beta", + "Script": "scripts/b.ps1", + "Type": "PS1", + "appid": null, + "appname": null, + "entryid": 2, + "haspayload": false, + "payloadref": null, + "payloadsha256": null, + "payloadsource": "smb", + "sortorder": 0 + }, + { + "DetectionMethod": "FileVersion", + "DetectionPath": "C:\\a.exe", + "DetectionValue": "1.0", + "Installer": "apps/a.exe", + "Name": "Alpha", + "Type": "EXE", + "appid": null, + "appname": null, + "entryid": 1, + "haspayload": false, + "payloadref": null, + "payloadsha256": null, + "payloadsource": "smb", + "sortorder": 1 + } + ], + "entrycount": 2, + "iscommon": false, + "manifestversion": "1.0", + "measuringtooltypeid": null, + "phase": "runtime", + "publishedversion": null, + "scopeid": 1, + "scopename": "gea-shopfloor-test" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18455,7 +26128,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "computertypeid": 3, + "description": "updated", + "entrycount": 0, + "iscommon": false, + "manifestversion": "1.0", + "measuringtooltypeid": null, + "phase": "runtime", + "publishedversion": null, + "scopeid": 1, + "scopename": "gea-shopfloor-test" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18495,6 +26189,10 @@ "type": "object", "additionalProperties": true, "description": "path: scopeid (int); body: JSON (fields not yet documented)" + }, + "example": { + "computertypeid": 3, + "description": "updated" } } } @@ -18518,7 +26216,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "computersplugin": false, + "phase": "runtime", + "rows": [ + { + "appid": 1, + "appname": "PC-DMIS", + "coveragenote": "computers plugin not installed; install counts unavailable", + "entryid": 1, + "entryname": "PC-DMIS 2019", + "expectedversion": "2019 R1", + "installedcount": null, + "versionmatchcount": null + } + ], + "scopeid": 1, + "scopename": "gea-shopfloor-cmm" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18569,7 +26294,42 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "InUseCheck": { + "Behavior": "CloseAndReopen", + "Processes": [ + { + "ExePath": "C:\\PCDLRN.exe", + "GracefulCloseTimeoutSec": 15, + "Name": "PCDLRN" + } + ] + }, + "Installer": "apps/pcdmis.msi", + "LogFile": "C:\\Logs\\pcdmis.log", + "Name": "PC-DMIS", + "PCTypesStrict": true, + "PreEnrollment": true, + "Type": "MSI", + "appid": null, + "appname": null, + "entryid": 1, + "haspayload": false, + "payloadref": null, + "payloadsha256": null, + "payloadsource": "smb", + "sortorder": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18609,6 +26369,24 @@ "type": "object", "additionalProperties": true, "description": "path: scopeid (int); body: JSON (fields not yet documented)" + }, + "example": { + "InUseCheck": { + "Behavior": "CloseAndReopen", + "Processes": [ + { + "ExePath": "C:\\PCDLRN.exe", + "GracefulCloseTimeoutSec": 15, + "Name": "PCDLRN" + } + ] + }, + "Installer": "apps/pcdmis.msi", + "LogFile": "C:\\Logs\\pcdmis.log", + "Name": "PC-DMIS", + "PCTypesStrict": true, + "PreEnrollment": true, + "Type": "MSI" } } } @@ -18632,7 +26410,22 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "order": [ + 2, + 1 + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18672,6 +26465,12 @@ "type": "object", "additionalProperties": true, "description": "path: scopeid (int); body: JSON (fields not yet documented)" + }, + "example": { + "order": [ + 2, + 1 + ] } } } @@ -18695,7 +26494,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "path": "" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18758,7 +26569,37 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "manifest": { + "Applications": [ + { + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\Alpha", + "Installer": "apps/alpha.msi", + "Name": "Alpha", + "Type": "MSI" + }, + { + "DetectionMethod": "Always", + "Name": "Beta", + "Script": "scripts/beta.ps1", + "Type": "PS1" + } + ], + "Version": "2.6" + }, + "scopename": "gea-shopfloor-cmm" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18809,7 +26650,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "versionnumber": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18849,6 +26702,9 @@ "type": "object", "additionalProperties": true, "description": "path: scopeid (int); body: JSON (fields not yet documented)" + }, + "example": { + "notes": "v1" } } } @@ -18872,7 +26728,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -18923,7 +26781,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "versionnumber": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -18963,6 +26833,9 @@ "type": "object", "additionalProperties": true, "description": "path: scopeid (int); body: JSON (fields not yet documented)" + }, + "example": { + "versionnumber": 1 } } } @@ -18986,7 +26859,38 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "applied": [ + "CLM (untagged)", + "PC-DMIS 2019" + ], + "filtered": [ + { + "filteredby": [ + "_CmmVersion" + ], + "name": "PC-DMIS 2016" + } + ], + "profile": { + "cmmversion": "2019", + "hostname": "", + "machinenumber": null, + "pctype": "gea-shopfloor-cmm", + "phase": "runtime", + "subtype": null + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19016,6 +26920,46 @@ "schema": { "type": "integer" } + }, + { + "name": "cmmversion", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "hostname", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "machinenumber", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "pctype", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "subtype", + "in": "query", + "required": false, + "schema": { + "type": "string" + } } ] } @@ -19037,7 +26981,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "iscurrent": false, + "notes": "v2", + "publishedat": "2026-01-01T00:00:00.000000Z", + "publishedby": 1, + "versionnumber": 2 + }, + { + "iscurrent": true, + "notes": "v1", + "publishedat": "2026-01-01T00:00:00.000000Z", + "publishedby": 1, + "versionnumber": 1 + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19088,7 +27057,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "manifest": { + "Applications": [ + { + "Name": "Alpha", + "Type": "MSI" + }, + { + "Name": "Beta", + "Type": "PS1" + } + ], + "Version": "1.0" + }, + "versionnumber": 2 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19147,7 +27141,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "canedit": false, + "checklistitems": 0, + "createdat": "2026-01-01T00:00:00.000000Z", + "guideid": 1, + "ispublished": true, + "publishedat": "2026-01-01T00:00:00.000000Z", + "revision": 2, + "slug": "published-procedure", + "status": "published", + "summary": null, + "tags": [], + "title": "Published procedure", + "updatedat": "2026-01-01T00:00:00.000000Z" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19165,7 +27185,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "q", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -19183,7 +27221,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "blocks": [], + "createdat": "2026-01-01T00:00:00.000000Z", + "guideid": 1, + "publishedat": null, + "revision": 1, + "slug": "replacing-a-marker-controler", + "status": "draft", + "summary": null, + "tags": [], + "title": "Replacing a marker controler", + "updatedat": "2026-01-01T00:00:00.000000Z" + }, + "message": "Guide created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19210,6 +27271,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "blocks": [], + "title": "Replacing a marker controler" } } } @@ -19233,7 +27298,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -19282,7 +27349,31 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "blocks": [], + "createdat": "2026-01-01T00:00:00.000000Z", + "guideid": 1, + "publishedat": null, + "revision": 2, + "saved": true, + "slug": "replacing-a-marker-controler", + "status": "draft", + "summary": null, + "tags": [], + "title": "Replacing a marker controller", + "updatedat": "2026-01-01T00:00:00.000000Z" + }, + "message": "Saved", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19322,6 +27413,10 @@ "type": "object", "additionalProperties": true, "description": "path: guideid (int); body: JSON (fields not yet documented)" + }, + "example": { + "blocks": [], + "title": "Replacing a marker controller" } } } @@ -19345,7 +27440,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -19408,7 +27505,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -19479,7 +27578,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -19530,7 +27631,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -19593,7 +27696,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -19644,7 +27749,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -19695,7 +27802,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "bytesize": 40, + "createdat": "2026-01-01T00:00:00.000000Z", + "filename": "screenshot.png", + "guideid": null, + "guideimageid": 1, + "mimetype": "image/png", + "url": "/api/guides/images/1" + }, + "message": "Image uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19745,7 +27871,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -19796,7 +27924,35 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "blocks": [ + { + "id": "b1", + "text": "secret draft wording", + "type": "paragraph" + } + ], + "createdat": "2026-01-01T00:00:00.000000Z", + "createdby": "", + "guideid": 1, + "guiderevisionid": 1, + "note": null, + "revision": 1, + "shorthash": "", + "summary": null, + "tags": [], + "title": "Published procedure" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19847,7 +28003,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19885,7 +28051,74 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "appid": 1, + "application": { + "appid": 1, + "appname": "Spotfire" + }, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "install", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 3, + "linkurl": "https://kb.example/c", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "Spotfire install guide" + }, + { + "appid": 1, + "application": { + "appid": 1, + "appname": "Spotfire" + }, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "export", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 2, + "linkurl": "https://kb.example/b", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "Export a visualization" + }, + { + "appid": 1, + "application": { + "appid": 1, + "appname": "Spotfire" + }, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "login", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 1, + "linkurl": "https://kb.example/a", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "Dashboard login steps" + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 3, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19903,7 +28136,84 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "appid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "linkurl", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "order", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "desc" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "shortdescription", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "clicks" + } + } + ] }, "post": { "tags": [ @@ -19921,7 +28231,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appid": null, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "printer reset", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 1, + "linkurl": "https://kb.example/printer-reset", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "How to reset a printer" + }, + "message": "Article created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -19948,6 +28280,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "keywords": "printer reset", + "linkurl": "https://kb.example/printer-reset", + "shortdescription": "How to reset a printer" } } } @@ -19971,7 +28308,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20020,7 +28359,29 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "appid": null, + "application": null, + "clicks": 0, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "keywords": "printer reset", + "lastupdated": "2026-01-01T00:00:00.000000Z", + "linkid": 1, + "linkurl": "https://kb.example/printer-reset", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "shortdescription": "How to reset a printer" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20069,7 +28430,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20132,7 +28495,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20195,7 +28560,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "totalarticles": 0, + "totalclicks": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20233,7 +28611,78 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assetid": 1, + "assetnumber": "0410", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "machine", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "dualpathpartner": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "machine": { + "assetid": 1, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": null, + "machineid": 1, + "machinetypeid": 1, + "machinetypename": "Part Washer", + "maintenanceintervaldays": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": null, + "requiresmanualconfig": false, + "vendorid": 1, + "vendorname": "Acme Industrial" + }, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Cell 4 washer", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20251,7 +28700,141 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "assetnumber", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "businessunit_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "dir", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "asc" + } + }, + { + "name": "location_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "assetnumber" + } + }, + { + "name": "type_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "typeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "vendor_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "vendorid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -20269,7 +28852,66 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "MAINT-DATE-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "machine", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "machine": { + "assetid": 1, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": "2026-01-01", + "machineid": 1, + "machinetypeid": null, + "maintenanceintervaldays": null, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": "2026-01-01", + "requiresmanualconfig": false, + "vendorid": null + }, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Maintenance date probe", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "message": "Machine created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20296,6 +28938,12 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "assetnumber": "MAINT-DATE-1", + "lastmaintenancedate": "2026-01-01", + "name": "Maintenance date probe", + "nextmaintenancedate": "2026-01-01" } } } @@ -20319,7 +28967,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20368,7 +29018,68 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "2001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "machine", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "dualpathpartner": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "machine": { + "assetid": 1, + "controllermodelid": null, + "controllervendorid": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "imageurl": "/api/models/images/model-1.png", + "isactive": true, + "islocationonly": false, + "lastmaintenancedate": null, + "machineid": 1, + "machinetypeid": null, + "maintenanceintervaldays": null, + "modelname": "IMG-MODEL-1", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextmaintenancedate": null, + "requiresmanualconfig": false, + "vendorid": null + }, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20417,7 +29128,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20480,7 +29193,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20531,7 +29246,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20569,7 +29294,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "bystatus": [ + { + "count": 1, + "status": "In Use" + } + ], + "bytype": [], + "total": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20607,7 +29351,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20625,7 +29387,51 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -20643,7 +29449,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20693,7 +29501,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20742,7 +29552,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20791,7 +29603,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -20854,7 +29668,75 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assetid": 26, + "assetnumber": "MT-PAGE-05", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "measuring_tool", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "measuringtool": { + "assetid": 26, + "calibrationintervaldays": null, + "calibrationprovider": null, + "calibrationstatus": "overdue", + "calibrationstatuscolor": "#F44336", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "lastcalibrationdate": null, + "measuringtoolid": 26, + "measuringtooltypeid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextcalibrationdate": "2026-01-01", + "notes": null + }, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Paged tool 5", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 26, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 2, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20872,7 +29754,91 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "assetnumber", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "calibrationstatus", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "statusid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "typeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -20890,7 +29856,68 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "MT-001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "measuring_tool", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-42", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "measuringtool": { + "assetid": 1, + "calibrationintervaldays": 365, + "calibrationprovider": "Metro Cal Lab", + "calibrationstatus": "current", + "calibrationstatuscolor": "#4CAF50", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "lastcalibrationdate": "2026-01-01", + "measuringtoolid": 1, + "measuringtooltypecolor": "#14abef", + "measuringtooltypeid": 1, + "measuringtooltypename": "Caliper", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextcalibrationdate": "2026-01-01", + "notes": null + }, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Bench caliper", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "message": "Measuring tool created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20917,6 +29944,18 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "assetnumber": "MT-001", + "calibrationintervaldays": 365, + "calibrationprovider": "Metro Cal Lab", + "gaugelabreference": "GL-42", + "lastcalibrationdate": "2026-01-01", + "measuringtooltypeid": 1, + "name": "Bench caliper", + "nextcalibrationdate": "2026-01-01", + "serialnumber": "", + "statusid": 1 } } } @@ -20940,7 +29979,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Measuring tool deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -20989,7 +30038,67 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "MT-001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "measuring_tool", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-42", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "measuringtool": { + "assetid": 1, + "calibrationintervaldays": 365, + "calibrationprovider": "Metro Cal Lab", + "calibrationstatus": "current", + "calibrationstatuscolor": "#4CAF50", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "lastcalibrationdate": "2026-01-01", + "measuringtoolid": 1, + "measuringtooltypecolor": "#14abef", + "measuringtooltypeid": 1, + "measuringtooltypename": "Caliper", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextcalibrationdate": "2026-01-01", + "notes": null + }, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Bench caliper", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21038,7 +30147,66 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 20, + "assetnumber": "MT-AUDIT-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "measuring_tool", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "measuringtool": { + "assetid": 20, + "calibrationintervaldays": null, + "calibrationprovider": null, + "calibrationstatus": "current", + "calibrationstatuscolor": "#4CAF50", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "lastcalibrationdate": "2026-01-01", + "measuringtoolid": 20, + "measuringtooltypeid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "nextcalibrationdate": "2026-01-01", + "notes": null + }, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "After rename", + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 20, + "serialnumber": "", + "statuscolor": null, + "statusid": 1, + "statusname": "In Use" + }, + "message": "Measuring tool updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21078,6 +30246,11 @@ "type": "object", "additionalProperties": true, "description": "path: tool_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "calibrationprovider": "In-house", + "name": "Renamed tool", + "nextcalibrationdate": "2026-01-01" } } } @@ -21101,7 +30274,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -21152,7 +30327,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assetid": 4, + "color": "#F44336", + "label": "Overdue" + }, + { + "assetid": 6, + "color": "#F44336", + "label": "Overdue" + }, + { + "assetid": 16, + "color": "#F44336", + "label": "Overdue" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21190,7 +30391,36 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "buckets": { + "current": [], + "duesoon": [], + "overdue": [], + "unknown": [] + }, + "counts": { + "current": 0, + "duesoon": 0, + "overdue": 0, + "unknown": 0 + }, + "statuscolors": { + "current": "#4CAF50", + "duesoon": "#FF9800", + "overdue": "#F44336", + "unknown": "#9E9E9E" + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21228,7 +30458,54 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "color": "#7934f3", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Bore / hole diameter gage", + "isactive": true, + "measuringtooltypeid": 4, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Bore Gage" + }, + { + "color": "#14abef", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Vernier / digital caliper", + "isactive": true, + "measuringtooltypeid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Caliper" + }, + { + "color": "#e83e8c", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Reference gage block set", + "isactive": true, + "measuringtooltypeid": 7, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Gage Block Set" + }, + "" + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 8, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21246,7 +30523,51 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -21264,7 +30585,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "color": "#123456", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Pin gage set", + "isactive": true, + "measuringtooltypeid": 9, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Pin Gage" + }, + "message": "Measuring-tool type created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21291,6 +30631,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "color": "#123456", + "description": "Pin gage set", + "name": "Pin Gage" } } } @@ -21314,7 +30659,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Measuring-tool type deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21363,7 +30718,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -21412,7 +30769,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "color": "#123456", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": "Updated", + "isactive": true, + "measuringtooltypeid": 9, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Pin Gage" + }, + "message": "Measuring-tool type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21452,6 +30828,9 @@ "type": "object", "additionalProperties": true, "description": "path: type_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "description": "Updated" } } } @@ -21475,7 +30854,77 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assetid": 1, + "assetnumber": "NET-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "network_device", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "networkdevice": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "firmwareversion": null, + "hostname": "", + "isactive": true, + "ismanaged": false, + "ispoe": false, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdeviceid": 1, + "networkdevicetypeid": 1, + "networkdevicetypename": "Switch", + "portcount": null, + "rackunit": null, + "vendorid": 1, + "vendorname": "Cisco" + }, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21493,7 +30942,157 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "assetnumber", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "businessunit_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "dir", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "asc" + } + }, + { + "name": "location_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "managed", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "poe", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "hostname" + } + }, + { + "name": "type_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "typeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "vendor_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "vendorid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -21511,7 +31110,67 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "APNL-Dock-Door-4", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "network_device", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Dock Door 4", + "networkdevice": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "firmwareversion": null, + "hostname": "", + "isactive": true, + "ismanaged": false, + "ispoe": false, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdeviceid": 1, + "networkdevicetypeid": 1, + "networkdevicetypename": "Access Panel", + "portcount": null, + "rackunit": null, + "vendorid": null + }, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "message": "Network device created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21538,6 +31197,12 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "assetnumber": "SW-CORE-01", + "hostname": "", + "ipaddress": "", + "name": "Core switch" } } } @@ -21561,7 +31226,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -21610,7 +31277,65 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "AST-networkdevice", + "assettypecolor": null, + "assettypeid": 3, + "assettypename": "network_device", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-2", + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": "MNT-2", + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "networkdevice": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "firmwareversion": null, + "hostname": "", + "isactive": true, + "ismanaged": false, + "ispoe": false, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdeviceid": 1, + "networkdevicetypeid": null, + "portcount": null, + "rackunit": null, + "vendorid": null + }, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21659,7 +31384,66 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "AST-networkdevice", + "assettypecolor": null, + "assettypeid": 3, + "assettypename": "network_device", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-2", + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": "MNT-2", + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "networkdevice": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "firmwareversion": null, + "hostname": "", + "isactive": true, + "ismanaged": false, + "ispoe": false, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdeviceid": 1, + "networkdevicetypeid": null, + "portcount": null, + "rackunit": null, + "vendorid": null + }, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "serialnumber": "", + "statusid": 1 + }, + "message": "Network device updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21699,6 +31483,10 @@ "type": "object", "additionalProperties": true, "description": "path: device_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "gaugelabreference": "GL-2", + "maintenancereference": "MNT-2" } } } @@ -21722,7 +31510,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -21773,7 +31563,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -21824,7 +31616,23 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "bytype": [], + "byvendor": [], + "nonpoe": 0, + "poe": 0, + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21862,7 +31670,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21880,7 +31706,75 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "vlanid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -21898,7 +31792,40 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "broadcastaddress": null, + "cidr": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "dhcpenabled": true, + "dhcprangeend": null, + "dhcprangestart": null, + "dns1": null, + "dns2": null, + "gatewayip": null, + "isactive": true, + "locationid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "Attached", + "networkaddress": null, + "subnetid": 1, + "subnetmask": null, + "subnettype": null, + "vlanid": 1, + "vlanname": "In use", + "vlannumber": 77 + }, + "message": "Subnet created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -21925,6 +31852,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "cidr": "", + "name": "Attached", + "vlanid": 1 } } } @@ -21948,7 +31880,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -21997,7 +31931,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22046,7 +31982,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22109,7 +32047,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22127,7 +32083,51 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -22145,7 +32145,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "color": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "icon": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdevicetype": "Door Controller", + "networkdevicetypeid": 1, + "prefix": "DOOR" + }, + "message": "Network device type created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22172,6 +32193,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "networkdevicetype": "Door Controller", + "prefix": "DOOR" } } } @@ -22195,7 +32220,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22244,7 +32271,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22293,7 +32322,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "color": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "icon": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "networkdevicetype": "Door Controller", + "networkdevicetypeid": 1, + "prefix": "DR" + }, + "message": "Network device type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22333,6 +32383,9 @@ "type": "object", "additionalProperties": true, "description": "path: type_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "prefix": "DR" } } } @@ -22356,7 +32409,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22374,7 +32445,59 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -22392,7 +32515,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000Z", + "description": null, + "isactive": true, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": "VLAN 4094", + "subnetcount": 0, + "vlanid": 1, + "vlannumber": 4094, + "vlantype": null + }, + "message": "VLAN created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22419,6 +32563,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "name": "VLAN 4094", + "vlannumber": 4094 } } } @@ -22442,7 +32590,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22491,7 +32641,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22540,7 +32692,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22603,7 +32757,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22621,7 +32793,84 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "current", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "false" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "ticketnumber", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "type_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "typeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -22639,7 +32888,49 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "alertfleet": true, + "alertscope": { + "computertype": "CMM PC", + "hostname": [ + "", + "" + ] + }, + "alerttimeout": 0, + "appid": null, + "businessunitid": null, + "employeename": "", + "employeesso": "", + "enddate": null, + "endtime": null, + "isactive": true, + "iscurrent": true, + "isshopfloor": false, + "link": null, + "linkurl": null, + "message": "Line 3 is down", + "notification": "Line 3 is down", + "notificationid": 1, + "notificationtypeid": 1, + "startdate": "2026-01-01T00:00:00.000000+00:00", + "starttime": "2026-01-01T00:00:00.000000+00:00", + "ticketnumber": null, + "title": "Line 3 is down", + "typecolor": "#d93f3f", + "typename": "Fleet Alert" + }, + "message": "Notification created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22666,6 +32957,18 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "alertfleet": true, + "alertscope": { + "computertype": "CMM PC", + "hostname": [ + "", + "" + ] + }, + "notification": "Line 3 is down", + "notificationtypeid": 1 } } } @@ -22689,7 +32992,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22738,7 +33043,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -22787,7 +33094,43 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "alertfleet": false, + "alertscope": null, + "alerttimeout": 0, + "appid": null, + "businessunitid": null, + "employeename": "", + "employeesso": "", + "enddate": null, + "endtime": null, + "isactive": true, + "iscurrent": true, + "isshopfloor": false, + "link": null, + "linkurl": null, + "message": "Line 3 is down", + "notification": "Line 3 is down", + "notificationid": 1, + "notificationtypeid": 1, + "startdate": "2026-01-01T00:00:00.000000+00:00", + "starttime": "2026-01-01T00:00:00.000000+00:00", + "ticketnumber": null, + "title": "Line 3 is down", + "typecolor": "#d93f3f", + "typename": "Fleet Alert" + }, + "message": "Notification updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22827,6 +33170,10 @@ "type": "object", "additionalProperties": true, "description": "path: notification_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "alertfleet": null, + "alerttimeout": null } } } @@ -22850,7 +33197,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "notifications": [], + "total": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22888,7 +33248,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22906,7 +33276,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "end", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/notifications/dashboard/active": { @@ -22926,7 +33314,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22964,7 +33362,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "active": 0, + "bytype": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -22998,7 +33409,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23039,7 +33452,61 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "configversion": "2b7c2d2f543f", + "current": [ + { + "boardcategory": "Current Events", + "boardorder": 50, + "displaystyle": "grid", + "employeename": "", + "employeepicture": "", + "employeesso": "", + "endtime": null, + "isactive": true, + "isshopfloor": true, + "link": null, + "notification": "press down", + "notificationid": 2, + "resolved": false, + "starttime": null, + "ticketnumber": null, + "typecolor": "#17a2b8", + "typename": "Incident" + }, + { + "boardcategory": "Current Events", + "boardorder": 30, + "displaystyle": "grid", + "employeename": "", + "employeepicture": "", + "employeesso": "", + "endtime": null, + "isactive": true, + "isshopfloor": true, + "link": null, + "notification": "retooling", + "notificationid": 1, + "resolved": false, + "starttime": null, + "ticketnumber": null, + "typecolor": "#17a2b8", + "typename": "Change" + } + ], + "timestamp": "2026-01-01T00:00:00.000000", + "upcoming": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23051,7 +33518,17 @@ } } } - } + }, + "parameters": [ + { + "name": "businessunit", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/notifications/types": { @@ -23071,7 +33548,43 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "boardcategory": "Alerts", + "boardorder": 100, + "displaystyle": "grid", + "expirydays": null, + "expiryhour": null, + "expiryminute": 0, + "expirymode": "none", + "gracewindowminutes": 0, + "isactive": true, + "notificationtypeid": 1, + "showemployeephoto": "", + "splitperemployee": "", + "typecolor": "#17a2b8", + "typedescription": null, + "typename": "Awareness" + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23089,7 +33602,43 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -23107,7 +33656,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "boardcategory": "Alerts", + "boardorder": 100, + "displaystyle": "grid", + "expirydays": null, + "expiryhour": null, + "expiryminute": 0, + "expirymode": "none", + "gracewindowminutes": 0, + "isactive": true, + "notificationtypeid": 1, + "showemployeephoto": "", + "splitperemployee": "", + "typecolor": "#17a2b8", + "typedescription": null, + "typename": "Awareness" + }, + "message": "Notification type created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23134,6 +33710,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "boardcategory": "Alerts", + "displaystyle": "grid", + "typename": "Awareness" } } } @@ -23157,7 +33738,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "boardcategory": "Alerts", + "boardorder": 100, + "displaystyle": "grid", + "expirydays": null, + "expiryhour": null, + "expiryminute": 0, + "expirymode": "none", + "gracewindowminutes": 0, + "isactive": true, + "notificationtypeid": 1, + "showemployeephoto": "", + "splitperemployee": "", + "typecolor": "#17a2b8", + "typedescription": null, + "typename": "Awareness" + }, + "message": "Notification type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23197,6 +33805,9 @@ "type": "object", "additionalProperties": true, "description": "path: type_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "boardcategory": "Alerts" } } } @@ -23218,7 +33829,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "boardcategory": "Alerts", + "boardorder": 100, + "displaystyle": "grid", + "expirydays": null, + "expiryhour": null, + "expiryminute": 0, + "expirymode": "none", + "gracewindowminutes": 0, + "isactive": true, + "notificationtypeid": 1, + "showemployeephoto": "", + "splitperemployee": "", + "typecolor": "#17a2b8", + "typedescription": null, + "typename": "Awareness" + }, + "message": "Notification type updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23258,6 +33896,9 @@ "type": "object", "additionalProperties": true, "description": "path: type_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "boardcategory": "Alerts" } } } @@ -23281,7 +33922,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23332,7 +33975,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23379,7 +34024,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23425,7 +34072,43 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": "WJRP0117", + "imageurl": null, + "isactive": true, + "islowstock": true, + "itemcode": "3DP0001", + "itemdescription": null, + "itemname": "Gage block holder", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 0 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23443,7 +34126,60 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "lowstock", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -23461,7 +34197,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": "WJRP0117", + "imageurl": null, + "isactive": true, + "islowstock": true, + "itemcode": "3DP0001", + "itemdescription": null, + "itemname": "Gage block holder", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 0 + }, + "message": "Printed item created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23488,6 +34251,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "gagelabtag": "wjrp0117", + "itemname": "Gage block holder" } } } @@ -23511,7 +34278,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Printed item retired", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23560,7 +34337,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23609,7 +34388,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23672,7 +34453,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23735,7 +34518,38 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "fileid": 2, + "filename": "clip_v2.gcode", + "filesize": 8, + "printeditemid": 1, + "revision": 2, + "uploadedby": "testadmin", + "uploadeddate": "2026-01-01T00:00:00.000000Z", + "uploadnote": null + }, + { + "fileid": 1, + "filename": "clip_v1.stl", + "filesize": 10, + "printeditemid": 1, + "revision": 1, + "uploadedby": "testadmin", + "uploadeddate": "2026-01-01T00:00:00.000000Z", + "uploadnote": "initial" + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23784,7 +34598,27 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "fileid": 1, + "filename": "clip_v1.stl", + "filesize": 10, + "printeditemid": 1, + "revision": 1, + "uploadedby": "testadmin", + "uploadeddate": "2026-01-01T00:00:00.000000Z", + "uploadnote": "initial" + }, + "message": "Revision 1 uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23847,7 +34681,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23896,7 +34732,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -23959,7 +34797,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": null, + "imageurl": null, + "isactive": true, + "islowstock": false, + "itemcode": "3DP-9001", + "itemdescription": null, + "itemname": "Test clip", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 10 + }, + "message": "Stock added", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -23999,6 +34864,10 @@ "type": "object", "additionalProperties": true, "description": "path: item_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "badge": "", + "quantity": 10 } } } @@ -24022,7 +34891,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": null, + "imageurl": null, + "isactive": true, + "islowstock": true, + "itemcode": "3DP-9001", + "itemdescription": null, + "itemname": "Test clip", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 0 + }, + "message": "Printed item restored", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24086,7 +34982,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": "WJRP0117", + "imageurl": null, + "isactive": true, + "islowstock": true, + "itemcode": "3DP0001", + "itemdescription": null, + "itemname": "Gage block holder", + "latestrevision": null, + "lowstockthreshold": 5, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24131,7 +35053,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -24170,7 +35094,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "binlocation": null, + "createddate": "2026-01-01T00:00:00.000000Z", + "gagelabtag": "WJRP7000", + "imageurl": null, + "isactive": true, + "islowstock": false, + "itemcode": "3DP-7000", + "itemdescription": null, + "itemname": "Rev part", + "latestrevision": null, + "lowstockthreshold": 2, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "printeditemid": 1, + "printnotes": null, + "quantityonhand": 8 + }, + "message": "Took 1, 8 left", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24191,6 +35142,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "badge": "", + "itemcode": "WJRP7000|3", + "quantity": 1 } } } @@ -24214,7 +35170,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "columns": [ + "employeesso", + "employeename", + "takes", + "" + ], + "days": 30, + "rows": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24232,7 +35207,26 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "days", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 30 + } + }, + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/printedparts/reports/consumption": { @@ -24252,7 +35246,26 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "columns": [ + "itemcode", + "itemname", + "takes", + "" + ], + "days": 30, + "rows": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24270,7 +35283,26 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "days", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 30 + } + }, + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/printedparts/reports/stock": { @@ -24290,7 +35322,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "columns": [ + "itemcode", + "itemname", + "binlocation", + "" + ], + "rows": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24308,7 +35358,17 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/printers": { @@ -24328,7 +35388,80 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "assetid": 1, + "assetnumber": "PR-1", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "printer", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "ipaddress": "", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "printer": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "installpath": null, + "isactive": true, + "iscolor": false, + "iscsf": false, + "isduplex": false, + "isnetwork": true, + "modelname": "ZT411", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "pin": null, + "printerid": 1, + "printertypeid": 1, + "printertypename": "Thermal", + "sharename": null, + "vendorid": null, + "windowsname": null + }, + "serialnumber": "", + "statusid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24346,7 +35479,141 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "assetnumber", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "businessunit_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "businessunitid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "dir", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "asc" + } + }, + { + "name": "location_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "locationid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "hostname" + } + }, + { + "name": "type_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "typeid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "vendor_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "vendorid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] }, "post": { "tags": [ @@ -24364,7 +35631,71 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "SpoolsInspection-Xerox", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "printer", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "printer": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "installpath": null, + "isactive": true, + "iscolor": false, + "iscsf": false, + "isduplex": false, + "isnetwork": true, + "modelname": "VersaLink C7125", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "pin": null, + "printerid": 1, + "printertypeid": null, + "sharename": null, + "vendorfrommodel": true, + "vendorid": null, + "vendorname": "Xerox", + "windowsname": null + }, + "serialnumber": "", + "statusid": 1 + }, + "message": "Printer created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24391,6 +35722,13 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "assetnumber": "CSF01-Materials-HP", + "hostname": "", + "installpath": "", + "mapx": 120, + "mapy": 240 } } } @@ -24414,7 +35752,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -24463,7 +35803,71 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "PR-2001", + "assettypecolor": null, + "assettypeid": 1, + "assettypename": "printer", + "businessunitid": null, + "communications": [], + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "drivers": [], + "gaugelabreference": null, + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": null, + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "printer": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "imageurl": "/api/models/images/model-1.png", + "installpath": null, + "isactive": true, + "iscolor": false, + "iscsf": false, + "isduplex": false, + "isnetwork": true, + "modelname": "IMG-MODEL-1", + "modelnumberid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "pin": null, + "printerid": 1, + "printertypeid": null, + "sharename": null, + "vendorid": null, + "windowsname": null + }, + "serialnumber": "", + "statusid": 1 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24512,7 +35916,68 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "AST-printer", + "assettypecolor": null, + "assettypeid": 2, + "assettypename": "printer", + "businessunitid": null, + "createdby": "", + "createddate": "2026-01-01T00:00:00.000000Z", + "deletedby": null, + "deleteddate": null, + "gaugelabreference": "GL-2", + "isactive": true, + "levelid": null, + "locationcode": null, + "locationid": null, + "maintenancereference": "MNT-2", + "mapverifiedat": null, + "mapx": null, + "mapy": null, + "modifiedby": "", + "modifieddate": "2026-01-01T00:00:00.000000Z", + "name": null, + "notes": null, + "ownlevelid": null, + "ownlocationid": null, + "ownmapx": null, + "ownmapy": null, + "pluginid": 1, + "printer": { + "assetid": 1, + "createddate": "2026-01-01T00:00:00.000000Z", + "hostname": "", + "installpath": null, + "isactive": true, + "iscolor": false, + "iscsf": false, + "isduplex": false, + "isnetwork": true, + "modelnumberid": null, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "pin": null, + "printerid": 1, + "printertypeid": null, + "sharename": null, + "vendorid": null, + "windowsname": null + }, + "serialnumber": "", + "statusid": 1 + }, + "message": "Printer updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24552,6 +36017,10 @@ "type": "object", "additionalProperties": true, "description": "path: printer_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "gaugelabreference": "GL-2", + "maintenancereference": "MNT-2" } } } @@ -24575,7 +36044,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -24626,7 +36097,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 4, + "defaultprinterassetid": null, + "printerassetids": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24675,7 +36160,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 3, + "defaultprinterassetid": 4, + "printerassetids": [ + 4, + 5 + ] + }, + "message": "Printer assignment updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24715,6 +36218,13 @@ "type": "object", "additionalProperties": true, "description": "path: asset_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "defaultprinterassetid": 4, + "printerassetids": [ + 4, + 5 + ] } } } @@ -24738,7 +36248,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -24801,7 +36313,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -24852,7 +36366,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "bytype": [], + "byvendor": [], + "criticalsupplies": 0, + "lowsupplies": 0, + "online": 0, + "total": 0, + "totalprinters": 0 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24890,7 +36422,73 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "rows": [ + { + "iscritical": true, + "levelid": null, + "location": "Shop floor", + "mapx": null, + "mapy": null, + "printerid": 2, + "printername": "Bravo", + "supplies": [ + { + "level": "critical", + "text": "Black Toner 0%", + "title": "No part number on file for this model" + } + ], + "worstremaining": 0 + }, + { + "iscritical": true, + "levelid": null, + "location": "Shop floor", + "mapx": null, + "mapy": null, + "printerid": 3, + "printername": "Charlie", + "supplies": [ + { + "level": "critical", + "text": "Black Toner 2%", + "title": "No part number on file for this model" + } + ], + "worstremaining": 2 + }, + { + "iscritical": true, + "levelid": null, + "location": "Shop floor", + "mapx": null, + "mapy": null, + "printerid": 1, + "printername": "Alpha", + "supplies": [ + { + "level": "critical", + "text": "Black Toner 4%", + "title": "No part number on file for this model" + } + ], + "worstremaining": 4 + }, + "" + ], + "unavailable": null + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24928,7 +36526,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24946,7 +36554,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + } + ] }, "post": { "tags": [ @@ -24964,7 +36583,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "description": null, + "driverid": 1, + "drivername": "HP Universal Printing PCL 6", + "isactive": true, + "location": "", + "modelname": null, + "modelnumberid": null, + "name": "HP universal", + "vendorid": 1 + }, + "message": "Driver created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -24991,6 +36631,12 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "drivername": "HP Universal Printing PCL 6", + "location": "", + "name": "HP universal", + "vendorid": 1 } } } @@ -25014,7 +36660,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -25063,7 +36711,28 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "description": null, + "driverid": 1, + "drivername": "Xerox Global Print Driver PCL6", + "isactive": true, + "location": "", + "modelname": null, + "modelnumberid": null, + "name": "Xerox universal", + "vendorid": 2 + }, + "message": "Driver updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25103,6 +36772,10 @@ "type": "object", "additionalProperties": true, "description": "path: driver_id (int); body: JSON (fields not yet documented)" + }, + "example": { + "drivername": "Xerox Global Print Driver PCL6", + "vendorid": 2 } } } @@ -25127,7 +36800,73 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "1001", + "defaultprinterid": null, + "hostname": "", + "printers": [ + { + "assetid": 4, + "driverid": null, + "driverlocation": null, + "drivername": null, + "hostname": "", + "inheritedfromassetid": 3, + "installpath": null, + "ipaddress": "", + "isdefault": false, + "port": null, + "printerid": 1, + "queuename": "PRINTER-A", + "sharename": null, + "windowsname": "PRINTER-A" + }, + { + "assetid": 5, + "driverid": null, + "driverlocation": null, + "drivername": null, + "hostname": "", + "inheritedfromassetid": 3, + "installpath": null, + "ipaddress": "", + "isdefault": false, + "port": null, + "printerid": 2, + "queuename": "PRINTER-B", + "sharename": null, + "windowsname": "PRINTER-B" + }, + { + "assetid": 6, + "driverid": null, + "driverlocation": null, + "drivername": null, + "hostname": "", + "inheritedfromassetid": 3, + "installpath": null, + "ipaddress": "", + "isdefault": false, + "port": null, + "printerid": 3, + "queuename": "PRINTER-C", + "sharename": null, + "windowsname": "PRINTER-C" + } + ], + "source": "inherited" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25173,7 +36912,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -25185,7 +36926,17 @@ } } } - } + }, + "parameters": [ + { + "name": "printerids", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/printers/install-list": { @@ -25206,7 +36957,35 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "hostname": "", + "installpath": "", + "ipaddress": "", + "iscsf": false, + "levelid": null, + "locationname": null, + "machinenumber": "CSF01-Materials-HP", + "mapx": 120, + "mapy": 240, + "modelnumber": null, + "name": "CSF01-Materials-HP", + "printerid": 1, + "sharename": null, + "vendorname": "", + "windowsname": null + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25218,7 +36997,17 @@ } } } - } + }, + "parameters": [ + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/printers/lookup": { @@ -25238,7 +37027,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -25256,7 +37047,25 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "fqdn", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "ip", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/printers/lowsupplies": { @@ -25276,7 +37085,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "printers": [], + "summary": { + "critical": 0, + "low": 0, + "total_checked": 0 + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25314,7 +37140,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "supplycount": 1, + "vendor": "TestVendor", + "vendorid": 1 + } + ], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 1, + "totalpages": 1 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25332,7 +37184,67 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "vendor_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "vendorid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "withsupplies", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + } + ] } }, "/api/printers/models/{modelnumberid}/supplies": { @@ -25352,7 +37264,37 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "supplies": [ + { + "capacitytier": "standard", + "color": "black", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "marketingname": "414A Black", + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "modelsupplyid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "pageyield": 2400, + "partnumber": "W2020A", + "supplytype": "toner" + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25401,7 +37343,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "capacitytier": "standard", + "color": "black", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "marketingname": "414A Black", + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "modelsupplyid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "pageyield": 2400, + "partnumber": "W2020A", + "supplytype": "toner" + }, + "message": "Supply added", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25441,6 +37408,14 @@ "type": "object", "additionalProperties": true, "description": "path: modelnumberid (int); body: JSON (fields not yet documented)" + }, + "example": { + "capacitytier": "standard", + "color": "black", + "marketingname": "414A Black", + "pageyield": 2400, + "partnumber": "W2020A", + "supplytype": "toner" } } } @@ -25464,7 +37439,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -25515,7 +37492,108 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assetid": 1, + "assetnumber": "1001", + "hosts": [ + { + "assetid": 1, + "assetnumber": "1001", + "hostname": "", + "observedat": "2026-01-01T00:00:00.000000", + "queues": [ + { + "classification": "extra", + "driftfields": [], + "drivername": "HP Universal Printing PS", + "expecteddrivername": null, + "expectedportaddress": null, + "expectedqueuename": null, + "inheritedfromassetid": null, + "isassigneddefault": false, + "isdefault": true, + "isshared": false, + "portaddress": "", + "portname": "IP_10.20.0.11", + "printerassetid": 5, + "printerid": 1, + "printername": "Bay label printer", + "queuename": "PRINTER-A" + }, + { + "classification": "extra", + "driftfields": [], + "drivername": "HP Universal Printing PS", + "expecteddrivername": null, + "expectedportaddress": null, + "expectedqueuename": null, + "inheritedfromassetid": null, + "isassigneddefault": false, + "isdefault": false, + "isshared": false, + "portaddress": "", + "portname": "IP_10.20.0.12", + "printerassetid": 6, + "printerid": 2, + "printername": "Bay laser printer", + "queuename": "PRINTER-B" + }, + { + "classification": "unknown", + "driftfields": [], + "drivername": "HP Universal Printing PS", + "expecteddrivername": null, + "expectedportaddress": null, + "expectedqueuename": null, + "inheritedfromassetid": null, + "isassigneddefault": false, + "isdefault": false, + "isshared": false, + "portaddress": "", + "portname": "IP_10.20.0.99", + "printerassetid": null, + "printerid": null, + "printername": null, + "queuename": "Reception Copier" + } + ], + "seedcandidate": { + "defaultprinterassetid": 5, + "printerassetids": [ + 5, + 6 + ], + "skipped": [ + { + "drivername": "HP Universal Printing PS", + "isdefault": false, + "portaddress": "", + "portname": "IP_10.20.0.99", + "queuename": "Reception Copier" + } + ] + }, + "source": "none", + "summary": { + "drifted": 0, + "extra": 2, + "matching": 0, + "missing": 0, + "unknown": 1 + } + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25567,7 +37645,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "printerid": 1, + "windowsname": "HP-CSF04-Materials" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25579,7 +37670,25 @@ } } } - } + }, + "parameters": [ + { + "name": "format", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "machine", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/printers/supplies/{modelsupplyid}": { @@ -25599,7 +37708,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Supply deleted", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25648,7 +37767,32 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "capacitytier": "high", + "color": "black", + "createddate": "2026-01-01T00:00:00.000000Z", + "isactive": true, + "marketingname": "414X Black", + "modelnumber": "TestModel C999", + "modelnumberid": 1, + "modelsupplyid": 1, + "modifieddate": "2026-01-01T00:00:00.000000Z", + "notes": null, + "pageyield": null, + "partnumber": "W2020A", + "supplytype": "toner" + }, + "message": "Supply updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25688,6 +37832,10 @@ "type": "object", "additionalProperties": true, "description": "path: modelsupplyid (int); body: JSON (fields not yet documented)" + }, + "example": { + "capacitytier": "high", + "marketingname": "414X Black" } } } @@ -25711,7 +37859,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "available": false, + "cartridges": [], + "days": 90, + "horizondays": 14, + "orderlist": [], + "reason": "Zabbix is not configured or not reachable", + "unestimated": [] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25729,7 +37895,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "days", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 90 + } + } + ] } }, "/api/printers/supplies/meta": { @@ -25749,7 +37926,36 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "capacitytiers": [ + "standard", + "high", + "extrahigh", + "" + ], + "colors": [ + "black", + "cyan", + "magenta", + "" + ], + "supplytypes": [ + "toner", + "drum", + "waste", + "" + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25787,7 +37993,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "message": "Supply cache cleared", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25814,7 +38030,8 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" - } + }, + "example": {} } } } @@ -25837,7 +38054,25 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "pagination": { + "hasnext": false, + "hasprev": false, + "page": 1, + "perpage": 20, + "total": 0, + "totalpages": 0 + }, + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -25855,7 +38090,51 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -25873,7 +38152,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -25923,7 +38204,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -25972,7 +38255,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26021,7 +38306,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26084,7 +38371,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -26135,7 +38432,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26206,7 +38505,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26269,7 +38570,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26332,7 +38635,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26388,10 +38693,16 @@ "security": [], "responses": { "200": { - "description": "Success. Body is the success_response envelope: {status, data, meta}.", + "description": "Success. This route does NOT return the standard envelope; the example is a transcript of a real response.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "example": { + "basepath": "/api/slides/img/lobby/", + "interval": 10, + "slides": [], + "success": true, + "surface": "lobby" + } } } }, @@ -26403,7 +38714,18 @@ } } } - } + }, + "parameters": [ + { + "name": "surface", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "lobby" + } + } + ] } }, "/api/slides/img/{surface}/{filename}": { @@ -26419,7 +38741,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26474,7 +38798,23 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "createddate": "2026-01-01T00:00:00.000000", + "expiresat": "2026-01-01T00:00:00.000000", + "token": "", + "viewcount": 0, + "viewsremaining": 100 + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -26495,6 +38835,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "ciphertext": "", + "iv": "MTIzNDU2Nzg5MDEy", + "views": 100 } } } @@ -26514,7 +38859,19 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "available": false + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -26553,7 +38910,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "ciphertext": "", + "iv": "MTIzNDU2Nzg5MDEy" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -26610,7 +38980,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26628,7 +39000,52 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + } + ] }, "post": { "tags": [ @@ -26646,7 +39063,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26696,7 +39115,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26745,7 +39166,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26808,7 +39231,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26871,7 +39296,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26934,7 +39361,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -26964,6 +39393,31 @@ "schema": { "type": "string" } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } } ] } @@ -26985,7 +39439,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -27048,7 +39504,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -27066,7 +39524,52 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "badge", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "perpage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + } + ] } }, "/api/usb/checkouts/active": { @@ -27086,7 +39589,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -27104,7 +39609,18 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "badge", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + } + ] } }, "/api/usb/kiosk/checkin": { @@ -27125,7 +39641,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "device_id": "USB-1" + }, + "message": "USB-1 checked in", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27146,6 +39675,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "badge": "", + "device_id": "USB-1", + "forsomeoneelse": true } } } @@ -27170,7 +39704,21 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "device_id": "USB-1", + "holdername": "Dana Reyes" + }, + "message": "USB-1 checked out to Dana Reyes", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27191,6 +39739,10 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "badge": "", + "device_id": "USB-1" } } } @@ -27215,7 +39767,23 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "holdername": "Dana Reyes", + "locker_location": null, + "status": "checked-out" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27261,7 +39829,24 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [ + { + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "holdername": "Dana Reyes", + "locker_location": null + } + ], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27282,6 +39867,9 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "badge": "" } } } @@ -27305,7 +39893,20 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "expiresinminutes": 30, + "url": "/api/usb/kiosk/setup?code=" + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27344,7 +39945,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "available": [ + { + "device_desc": "Second", + "device_id": "USB-2", + "locker_location": null + } + ], + "name": "Dana Reyes", + "otherscount": 0, + "yours": [ + { + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "locker_location": null + } + ] + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27365,6 +39993,9 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "badge": "" } } } @@ -27388,7 +40019,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -27406,7 +40039,17 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "code", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] } }, "/api/usb/reports/audit": { @@ -27426,7 +40069,67 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "columns": [ + "timestamp", + "action", + "device_id", + "" + ], + "days": 365, + "rows": [ + { + "action": "check-in", + "badge": "", + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "locker_location": "", + "name": "Dana Reyes", + "sanitized": "", + "scanned_viruses": "", + "timestamp": "2026-01-01T00:00:00.000000" + }, + { + "action": "check-out", + "badge": "", + "device_desc": "Blue Kingston", + "device_id": "USB-1", + "locker_location": "", + "name": "Dana Reyes", + "sanitized": "", + "scanned_viruses": "", + "timestamp": "2026-01-01T00:00:00.000000" + }, + { + "action": "check-out", + "badge": "", + "device_desc": "Red SanDisk", + "device_id": "USB-2", + "locker_location": "", + "name": "Sam Okafor", + "sanitized": "", + "scanned_viruses": "", + "timestamp": "2026-01-01T00:00:00.000000" + } + ], + "summary": { + "checkins": 1, + "checkouts": 2, + "devices": 2, + "events": 3, + "people": 2 + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27464,7 +40167,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27482,7 +40195,50 @@ "403": { "description": "Authenticated, but not permitted." } - } + }, + "parameters": [ + { + "name": "active", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "true" + } + }, + { + "name": "assetid", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "servicetag", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "vendor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] }, "post": { "tags": [ @@ -27500,7 +40256,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assets": [], + "enddate": "2026-01-01", + "isactive": true, + "lastcheckeddate": null, + "notes": null, + "prooffilename": null, + "proofurl": null, + "provider": "manual", + "servicelevel": null, + "servicetag": "", + "startdate": null, + "status": "active", + "statuscolor": "#4CAF50", + "vendor": "Acme", + "warrantyid": 1 + }, + "message": "Warranty created", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27527,6 +40310,11 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" + }, + "example": { + "enddate": "2026-01-01", + "servicetag": "", + "vendor": "Acme" } } } @@ -27550,7 +40338,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -27599,7 +40389,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -27648,7 +40440,34 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "assets": [], + "enddate": null, + "isactive": true, + "lastcheckeddate": null, + "notes": null, + "prooffilename": null, + "proofurl": null, + "provider": "manual", + "servicelevel": null, + "servicetag": "", + "startdate": null, + "status": "unknown", + "statuscolor": "#9E9E9E", + "vendor": "Acme", + "warrantyid": 1 + }, + "message": "Warranty updated", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27688,6 +40507,9 @@ "type": "object", "additionalProperties": true, "description": "path: warrantyid (int); body: JSON (fields not yet documented)" + }, + "example": { + "enddate": "" } } } @@ -27711,7 +40533,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "enddate": null, + "isactive": true, + "lastcheckeddate": null, + "notes": null, + "prooffilename": null, + "proofurl": null, + "provider": "manual", + "servicelevel": null, + "servicetag": "", + "startdate": null, + "status": "unknown", + "statuscolor": "#9E9E9E", + "vendor": "Dell", + "warrantyid": 1 + }, + "message": "Proof removed", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27760,7 +40608,33 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "enddate": null, + "isactive": true, + "lastcheckeddate": null, + "notes": null, + "prooffilename": "Dell invoice 4471.pdf", + "proofurl": "/api/warranty/proof/warranty-1.pdf", + "provider": "manual", + "servicelevel": null, + "servicetag": "", + "startdate": null, + "status": "unknown", + "statuscolor": "#9E9E9E", + "vendor": "Dell", + "warrantyid": 1 + }, + "message": "Proof uploaded", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27823,7 +40697,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -27886,7 +40762,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -27937,7 +40815,17 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": [], + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -27975,7 +40863,9 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + } } } }, @@ -28027,7 +40917,30 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "buckets": { + "active": [], + "expired": [], + "expiring": [], + "unknown": [] + }, + "counts": { + "active": 0, + "expired": 0, + "expiring": 0, + "unknown": 0 + } + }, + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -28065,7 +40978,23 @@ "description": "Success. Body is the success_response envelope: {status, data, meta}.", "content": { "application/json": { - "$ref": "#/components/schemas/SuccessEnvelope" + "schema": { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + "example": { + "data": { + "candidates": 0, + "created": 0, + "matched": 0, + "updated": 0 + }, + "message": "No PCs need a warranty lookup.", + "meta": { + "requestid": "00000000", + "timestamp": "2026-01-01T00:00:00.000000Z" + }, + "status": "success" + } } } }, @@ -28084,6 +41013,17 @@ "description": "Authenticated, but not permitted." } }, + "parameters": [ + { + "name": "all", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "false" + } + } + ], "requestBody": { "required": true, "content": { @@ -28092,7 +41032,8 @@ "type": "object", "additionalProperties": true, "description": "body: JSON (fields not yet documented)" - } + }, + "example": {} } } } diff --git a/scripts/gen_openapi.py b/scripts/gen_openapi.py index 267714ac..9a82a0c1 100644 --- a/scripts/gen_openapi.py +++ b/scripts/gen_openapi.py @@ -30,19 +30,23 @@ satisfied without a credential. See AUTH_SCHEME and _security. Derived strings come from DECORATOR_AUTH, HANDLER_AUTH and INLINE_AUTH below, so a route whose gate this cannot see says so rather than guessing. -KNOWN LIMITATION: QUERY PARAMETERS ARE NOT DERIVED. Path arguments come out of -the rule, and a body is declared for the verbs that take one, but nothing here -reads request.args out of a handler - so every route whose real interface is a -query string ('?q=', '?page=', '?status=') publishes params as 'not documented' -and an operation with no `parameters` beyond its path. That is a gap in the -generated spec, not in the route: a machine client built from this document can -call those endpoints but cannot filter, search or page them. Filling it means -either a handler sweep for request.args reads - which cannot see a key built at -runtime, so it would be right most of the time and silently wrong the rest - or -writing the query contract into the inventory's PROSE half by hand, where a -human owns it. The prose half is the honest option and is where it should land. -The one query credential that IS expressed is the kiosk setup code, because it -is auth rather than a filter and rides in as a securityScheme. +QUERY PARAMETERS ARE DERIVED TOO, and on the same terms as auth: only what the +code says. The sweep reads each view's AST for request.args reads and for the +two helpers this repository reads arguments through, and emits ONLY the ones +whose name resolves to a literal. A key built at runtime produces no parameter +rather than a guessed one - see the section above build(). They land in the +inventory as `queryparams`, which is DERIVED like auth, not prose: hand-editing +it does not survive the next --refresh. + +EXAMPLES ARE HARVESTED, NOT WRITTEN. --harvest runs the test suite with this +file loaded as a pytest plugin, records what the test client actually sent and +actually got back, redacts it and folds it into the inventory. Nothing is +composed: an invented example body is a lie in a contract that a generated +client sends verbatim. Harvesting is optional and re-runnable - a checkout with +no tests, and a checkout that has never harvested, both generate a spec. + + venv/bin/python scripts/gen_openapi.py --harvest # whole suite + venv/bin/python scripts/gen_openapi.py --harvest tests/test_core """ import json @@ -191,36 +195,100 @@ def _request_body(verb, entry): prose. That is honest, and it is the difference between a machine client that can send a body and one that cannot send anything at all. """ + harvested = entry.get('requestexample') if verb not in ('post', 'put', 'patch'): - return None + # A DELETE that reads a body. Two here do, and one of them refuses + # without {"confirm": "OK"} - so the spec described a call that cannot + # succeed, and a client built from it fails on the day. The evidence is + # a transcript of a request the suite really sent; with no transcript + # this stays silent rather than offering every DELETE a body it ignores. + # A transcript proves the CLIENT sent a body, not that the ROUTE reads + # one. The suite posts {} to routes that ignore it, and publishing that + # as "this route reads a JSON body" is a contract claim the code does + # not support: DELETE /api/endpoints/agentkey never calls get_json. + # So the handler has to show a read before the body is declared. + if harvested is None or not entry.get('readsbody'): + return None + if harvested == {} or harvested is None: + # An empty body teaches nothing and reads as "send {}", which for + # a route with required fields is wrong. Declare the body, omit the + # example. + return { + 'required': False, + 'content': {'application/json': { + 'schema': {'type': 'object', 'additionalProperties': True, + 'description': 'This route reads a JSON body.'}, + }}, + } + return { + 'required': False, + 'content': {'application/json': { + 'schema': {'type': 'object', 'additionalProperties': True, + 'description': 'This route reads a JSON body. The ' + 'example is a request that worked.'}, + 'example': harvested, + }}, + } described = entry.get('params') or '' + media = { + 'schema': { + 'type': 'object', + 'additionalProperties': True, + 'description': described or 'See the endpoint description.', + } + } + # The one thing the schema cannot say: which fields. It is an open object + # because the inventory describes bodies in prose, so a harvested example is + # the only field list a reader gets - and it is a transcript of a body the + # suite actually sent, not a guess at one. + if harvested is not None: + media['example'] = harvested return { 'required': verb in ('post', 'put'), - 'content': { - 'application/json': { - 'schema': { - 'type': 'object', - 'additionalProperties': True, - 'description': described or 'See the endpoint description.', - } - } - }, + 'content': {'application/json': media}, } -def _responses(security, parameters): +def _is_envelope(example): + """Whether a harvested response is the success_response envelope. + + The envelope is `{status: 'success', data, meta}`. Anything else - a bare + list, a plain object, a manifest - is a route that answers in its own shape. + """ + return isinstance(example, dict) and example.get('status') == 'success' + + +def _responses(security, parameters, example=None): """The envelope, plus the failures a caller has to handle. One hardcoded 200 was the whole response section, so a generated client had no idea any call could fail, and 19 operations that do not return the envelope at all were documented as if they did. + + The 200 media type carried a bare `$ref` where OpenAPI expects a Media Type + Object, i.e. `{"schema": {"$ref": ...}}`. Redoc tolerated it; a strict + parser does not, and there is nowhere to hang an example on the wrong shape. """ + envelope = 'Success. Body is the success_response envelope: {status, data, meta}.' + success = {'schema': {'$ref': '#/components/schemas/SuccessEnvelope'}} + description = envelope + if example is not None: + success['example'] = example + # A harvested example is EVIDENCE. Nineteen routes here do not return + # the envelope, and every one of them was documented as if it did - a + # $ref that a generated client validates against and a reader writes + # code to. When the transcript disagrees with the envelope, the + # transcript is what the route actually returned, so the claim comes + # off rather than the example. + if not _is_envelope(example): + success = {'example': example} + description = ('Success. This route does NOT return the standard ' + 'envelope; the example is a transcript of a real ' + 'response.') responses = { '200': { - 'description': 'Success. Body is the success_response envelope: ' - '{status, data, meta}.', - 'content': {'application/json': { - '$ref': '#/components/schemas/SuccessEnvelope'}}, + 'description': description, + 'content': {'application/json': success}, }, 'default': { 'description': 'Error. Body is the error envelope; the code and ' @@ -256,6 +324,338 @@ def _summary(text, fallback): return (head[:cut] if cut > 40 else head).rstrip(' ,;:.+-/&|(') + '...' +# --------------------------------------------------------------------------- +# Derived query parameters +# --------------------------------------------------------------------------- +# +# A Flask rule carries its path arguments and nothing else, so a route whose +# real interface is '?code=' or '?search=' published an operation with no query +# parameters at all - 0 of 573. A machine client built from that document could +# call those endpoints but could not filter, search or page them, and +# /api/usb/kiosk/setup, where '?code=' is the ONLY way to call it successfully, +# said nothing. +# +# So the handler is read instead. This walks the view's AST for the reads that +# name their argument as a literal - request.args.get('x'), request.args['x'], +# request.args.getlist('x') - and for the two helpers this repository reads +# arguments through, shopdb.utils.pagination.get_pagination_params and +# shopdb.utils.queryargs.intarg/intargs. +# +# THE RULE IS: A NAME THAT DOES NOT RESOLVE TO A LITERAL IS NOT EMITTED. A key +# built at runtime, or read through a variable this cannot see, produces no +# parameter rather than a guessed one. The published spec is a contract, and a +# parameter that is not really there is worse than a missing one: a reader +# believes it, sends it, and is silently ignored. Silence is recoverable. +# +# Required is derived the same way. request.args['x'] raises without the +# argument, so it is required; a .get() call cannot be - it has a fallback, even +# when that fallback is None. Nothing here promotes a parameter to required +# because it looks important. + +# The argument-reading helpers, by the tail of the call. Each maps to the +# parameters that helper reads, which is a property of the helper and not of the +# route - so it is written once here rather than re-derived per view. +# +# get_pagination_params reads all three names and int()s them, which is why they +# publish as integers while a bare request.args.get() publishes as a string: the +# query string is text, and only a handler that converts makes it anything else. +PAGINATION_PARAMS = ( + {'name': 'page', 'type': 'integer', 'required': False, 'default': 1}, + {'name': 'perpage', 'type': 'integer', 'required': False}, + # The legacy spelling, still read as a fallback by the same helper. A caller + # reading only the spec would never find it, and a caller migrating from it + # would not know it still works. + {'name': 'per_page', 'type': 'integer', 'required': False}, +) + + +def _constant_string(node, constants): + """The literal string a call argument names, or None. + + Two forms resolve: a string literal, and a module-level Name bound to one + (plugins/endpoints/api/bootstrap.py reads its query token through + QUERY_TOKEN_ARG). Anything else - an f-string, a variable from an argument, + a key built at runtime - returns None and is dropped, which is the whole + honesty rule of this section. + """ + import ast + if isinstance(node, ast.Constant) and isinstance(node.value, str): + return node.value + if isinstance(node, ast.Name): + return constants.get(node.id) + return None + + +def _wire_type(call): + """The OpenAPI type for a request.args read, from its `type=` converter. + + A query string is text. Werkzeug returns a string unless the caller passed + type=int (or float, or bool), so that keyword is the only evidence here that + the value is anything else, and without it the parameter publishes as a + string. + """ + import ast + for keyword in call.keywords: + if keyword.arg != 'type': + continue + name = getattr(keyword.value, 'id', '') + return {'int': 'integer', 'float': 'number', 'bool': 'boolean'}.get(name, 'string') + return 'string' + + +def _literal_default(node, wiretype): + """A default worth publishing, or None. + + Only literals. `request.args.get('sort', DEFAULT_SORT)` has a default this + cannot see, and publishing 'DEFAULT_SORT' as the value would be a lie in the + contract; publishing no default is merely incomplete. + + A numeric default under a string type is stringified rather than dropped, + because that is what the caller actually puts on the wire: `?page=1`. + """ + import ast + if not isinstance(node, ast.Constant) or node.value is None: + return None + value = node.value + if isinstance(value, bool): + return value if wiretype == 'boolean' else str(value).lower() + if isinstance(value, (int, float)): + return value if wiretype in ('integer', 'number') else str(value) + if isinstance(value, str): + return value + return None + + +def _args_read(call, constants): + """One parameter from a request.args.get/getlist call, or None.""" + import ast + attribute = call.func + if not isinstance(attribute, ast.Attribute): + return None + if attribute.attr not in ('get', 'getlist'): + return None + # `.args.get(...)`: the receiver is what matters, not whether it + # is spelled `request` or a handler's `request_obj` parameter. + owner = attribute.value + if not isinstance(owner, ast.Attribute) or owner.attr != 'args': + return None + if not call.args: + return None + name = _constant_string(call.args[0], constants) + if not name: + return None + if attribute.attr == 'getlist': + # Repeatable: '?id=1&id=2'. Published as an array of strings, which is + # what getlist returns without a converter. + return {'name': name, 'type': 'array', 'required': False} + wiretype = _wire_type(call) + parameter = {'name': name, 'type': wiretype, 'required': False} + fallback = None + if len(call.args) > 1: + fallback = call.args[1] + for keyword in call.keywords: + if keyword.arg == 'default': + fallback = keyword.value + if fallback is not None: + default = _literal_default(fallback, wiretype) + if default is not None: + parameter['default'] = default + return parameter + + +def _helper_read(call, constants): + """Parameters from one call to an argument-reading helper.""" + import ast + tail = call.func.attr if isinstance(call.func, ast.Attribute) else getattr(call.func, 'id', '') + if tail == 'get_pagination_params': + return [dict(item) for item in PAGINATION_PARAMS] + if tail == 'intarg': + if not call.args: + return [] + name = _constant_string(call.args[0], constants) + if not name: + return [] + parameter = {'name': name, 'type': 'integer', 'required': False} + fallback = call.args[1] if len(call.args) > 1 else None + for keyword in call.keywords: + if keyword.arg == 'default': + fallback = keyword.value + if fallback is not None: + default = _literal_default(fallback, 'integer') + if default is not None: + parameter['default'] = default + return [parameter] + if tail == 'intargs': + found = [] + for node in call.args: + name = _constant_string(node, constants) + if name: + found.append({'name': name, 'type': 'integer', 'required': False}) + return found + return [] + + +def _args_subscript(node, constants): + """A parameter from `request.args['x']`, which is REQUIRED. + + Werkzeug raises a 400 BadRequestKeyError when the argument is absent, so + this is the one read in the language that proves the caller must send it. + """ + import ast + owner = node.value + if not isinstance(owner, ast.Attribute) or owner.attr != 'args': + return None + name = _constant_string(node.slice, constants) + if not name: + return None + return {'name': name, 'type': 'string', 'required': True} + + +def _merge_parameter(found, parameter): + """Fold one read into the set, keeping the strongest evidence. + + The same argument is often read twice in one handler - once to test it, once + to use it - and the two reads do not always carry the same evidence. Take + required from either (one required read is proof), the more specific type, + and the first default seen. + """ + existing = found.get(parameter['name']) + if existing is None: + found[parameter['name']] = dict(parameter) + return + if parameter.get('required'): + existing['required'] = True + if existing.get('type') == 'string' and parameter.get('type') != 'string': + existing['type'] = parameter['type'] + if 'default' not in existing and 'default' in parameter: + existing['default'] = parameter['default'] + + +def _module_constants(tree): + """Module-level names bound to a string literal, for name resolution.""" + import ast + constants = {} + for node in tree.body: + if not isinstance(node, ast.Assign): + continue + if not isinstance(node.value, ast.Constant) or not isinstance(node.value.value, str): + continue + for target in node.targets: + if isinstance(target, ast.Name): + constants[target.id] = node.value.value + return constants + + +def _query_index(filename, _cache={}): + """{function name: [parameter, ...]} of derived query arguments for one file. + + Read from the source for the same reason the auth sweep is: by the time a + view is in url_map, functools.wraps has left nothing of its body to inspect. + + ast.walk over the function covers a nested def as well, which is deliberate + - a handler that reads its arguments inside an inner function still reads + them. + """ + import ast + if filename in _cache: + return _cache[filename] + index = {} + try: + with open(filename, 'r', encoding='utf-8') as handle: + tree = ast.parse(handle.read()) + except (OSError, SyntaxError): + _cache[filename] = index + return index + constants = _module_constants(tree) + for node in ast.walk(tree): + if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): + continue + found = {} + for item in ast.walk(node): + if isinstance(item, ast.Call): + parameter = _args_read(item, constants) + if parameter: + _merge_parameter(found, parameter) + for parameter in _helper_read(item, constants): + _merge_parameter(found, parameter) + elif isinstance(item, ast.Subscript): + parameter = _args_subscript(item, constants) + if parameter: + _merge_parameter(found, parameter) + index[node.name] = [found[name] for name in sorted(found)] + _cache[filename] = index + return index + + +def _reads_a_json_body(view): + """True when the handler really reads a request body. + + Evidence has to come from the HANDLER, not from a transcript. The suite + sends {} to routes that ignore it, and a transcript-driven guess published + "this route reads a JSON body" on DELETE /api/endpoints/agentkey, which + never calls get_json. A client built from that would send a body to a route + that discards it, and believe the body mattered. + + Matches request.get_json(...), request.json, request.data, request.form and + request.files, on any receiver named request, anywhere in the function. + """ + import ast + import inspect + import textwrap + try: + original = inspect.unwrap(view) + source = textwrap.dedent(inspect.getsource(original)) + tree = ast.parse(source) + except (OSError, TypeError, SyntaxError, IndentationError): + # A view defined dynamically has no readable source. Silence, not a + # guess: this decides whether the published contract claims a body. + return False + for node in ast.walk(tree): + if not isinstance(node, ast.Attribute): + continue + if node.attr not in ('get_json', 'json', 'data', 'form', 'files'): + continue + base = node.value + if isinstance(base, ast.Name) and base.id == 'request': + return True + return False + + +def _query_parameters(view): + """Derived query parameters for one url_map view, sorted by name.""" + import inspect + original = inspect.unwrap(view) + filename = inspect.getsourcefile(original) or '' + return _query_index(filename).get(original.__name__, []) + + +def _query_parameter_objects(entry): + """The inventory's derived `queryparams` as OpenAPI parameter objects. + + Defensive about the key being absent: an inventory written before this + existed, or one hand-trimmed, still generates a spec. + """ + parameters = [] + for parameter in entry.get('queryparams') or []: + name = parameter.get('name') + if not name: + continue + wiretype = parameter.get('type') or 'string' + if wiretype == 'array': + schema = {'type': 'array', 'items': {'type': 'string'}} + else: + schema = {'type': wiretype} + if 'default' in parameter: + schema['default'] = parameter['default'] + parameters.append({ + 'name': name, + 'in': 'query', + 'required': bool(parameter.get('required')), + 'schema': schema, + }) + return parameters + + def build(surfaces): paths = {} tags = [] @@ -282,13 +682,20 @@ def build(surfaces): if e.get('example'): desc.append('\n\n**Example:**\n```\n' + e['example'] + '\n```') security = _security(e.get('auth')) - parameters = _path_parameters(e.get('path')) + pathparameters = _path_parameters(e.get('path')) + # Path first, then query, so a reader sees the URL in the order + # they type it. + parameters = pathparameters + _query_parameter_objects(e) operation = { 'tags': [s['surface']], 'summary': _summary(e.get('purpose'), path), 'description': ''.join(desc), 'security': security, - 'responses': _responses(security, parameters), + # Only PATH parameters decide whether 404 is documented. A + # query filter that matches nothing is an empty list and a + # 200, not a missing record. + 'responses': _responses(security, pathparameters, + e.get('responseexample')), } if parameters: operation['parameters'] = parameters @@ -747,6 +1154,18 @@ def _existing_prose(): return prose +def _write_inventory(document): + """One writer, because --refresh and --harvest both rewrite this file. + + Same indent and same trailing newline from both, so a harvest that changes + nothing changes no bytes and the diff of a regenerated inventory is only + what actually moved. + """ + with open(INVENTORY, 'w', encoding='utf-8') as handle: + json.dump(document, handle, indent=2) + handle.write('\n') + + def _inventory_app(): """The app, with every bundled plugin enabled. @@ -816,6 +1235,20 @@ def refresh_inventory(): 'purpose': entry.get('purpose') or _seed_purpose(view, endpoint), 'example': entry.get('example') or _seed_example(path, methods, auth), }) + # DERIVED, like auth: rewritten outright rather than preserved. A query + # argument the handler no longer reads has to leave the contract, and a + # hand-written one has nothing holding it true. + derived = _query_parameters(view) + if derived: + entry['queryparams'] = derived + else: + entry.pop('queryparams', None) + # Same rule: derived, not preserved. A handler that stops reading a body + # must stop advertising one. + if _reads_a_json_body(view): + entry['readsbody'] = True + else: + entry.pop('readsbody', None) # Fixed key order, so a refresh that changes nothing changes no bytes. ordered = {key: entry[key] for key in ('method', 'path', 'auth', 'params', 'purpose', 'example')} @@ -825,9 +1258,7 @@ def refresh_inventory(): document = [{'surface': name, 'endpoints': entries} for name, entries in sorted(surfaces.items())] - with open(INVENTORY, 'w', encoding='utf-8') as handle: - json.dump(document, handle, indent=2) - handle.write('\n') + _write_inventory(document) total = sum(len(surface['endpoints']) for surface in document) print('refreshed %s: %d entries in %d surfaces (%d new)' @@ -841,11 +1272,488 @@ def refresh_inventory(): print(' review %s' % line) -def main(): - if '--refresh' in sys.argv[1:]: - refresh_inventory() +# --------------------------------------------------------------------------- +# Harvested examples, and the redaction that has to happen first +# --------------------------------------------------------------------------- +# +# 0 of 573 operations carried a machine-readable example, which is the single +# thing people mean when they ask for usable API documentation. Writing 573 of +# them by hand is not going to happen, and inventing them is forbidden: an +# example body that nobody ever sent is a lie in a contract that a generated +# client will send verbatim. +# +# The examples already exist. The test suite posts real bodies at the real app +# and asserts the real responses. So --harvest runs pytest with this file +# loaded as a plugin, records what the test client actually sent and got back, +# and folds it into the inventory. Nothing is composed here; every example is a +# transcript. +# +# Harvesting is OPTIONAL and RE-RUNNABLE. gen_openapi.py generates a spec with +# no harvest data at all (that is the normal case in a published checkout, which +# has no tests), and a second harvest overwrites the first rather than +# accumulating. + +HARVEST_DIR_VAR = 'SHOPDB_OPENAPI_HARVEST_DIR' + +# The keys and values that never reach the published spec. +# +# THIS FILE IS SERVED ON PRODUCTION AND PUBLISHED TO A WIKI. A harvested body is +# whatever a test happened to build, and tests are written with real-looking +# material: a login body carries a password, an agent body carries its token, a +# kiosk body carries a badge number, an endpoint body carries a hostname and an +# address. None of that is dangerous in a test file, and all of it is dangerous +# on a public page - a reader cannot tell a fixture from a fact, and neither can +# a scraper. +# +# Matched on the KEY first, because the key is the reliable signal: a field +# called 'passwordhash' is a credential whatever it happens to contain today, +# including when a fixture leaves it empty. Then on the VALUE, for the material +# that carries no name - an address in a free-text field, a JWT in a list. +SECRET_KEY_PATTERN = re.compile( + r'pass|pwd|secret|token|api[-_ ]?key|privatekey|credential|authoriz' + r'|displayprefix' + r'|cookie|salt|signature|sessionid|\botp\b|passphrase|hash', re.IGNORECASE) + +# A person. Not a secret, but not ours to publish either: these pages are read +# by other sites and by the public, and a name or a badge number identifies +# somebody who never agreed to appear in API documentation. +PERSON_KEY_PATTERN = re.compile( + r'username|email|firstname|lastname|fullname|displayname|badge|employee' + r'|createdby|updatedby|modifiedby|assignedto|checkedoutby|reservedby' + r'|requestedby|approvedby|\bowner|contactname|phone', re.IGNORECASE) + +# A machine. ADR-015: one plant's server name, its FQDN or its internal networks +# are neither ours to publish nor meaningful to any other site reading this. +HOST_KEY_PATTERN = re.compile( + r'hostname|fqdn|ipaddress|\bip\b|macaddress|serialnumber|servicetag' + r'|computername|machinename|sharepath|uncpath|netbios', re.IGNORECASE) + +# Searched, not matched: an address or a token embedded in a free-text field is +# as published as one that is the whole value, and a sentence that contains one +# is scrubbed entire rather than partially. +# A per-request value, normalised rather than published as recorded. +# +# WHY. A transcript carries the instant it was taken and the id of the request +# that produced it, and both are different on every run. Published verbatim, +# re-harvesting rewrote 313 of 320 examples with no change of meaning - a diff +# nobody can review, over a file that is committed and published. An example +# exists to show a reader the FORMAT of a field, not the moment one call +# happened, so the format is kept exactly and the value is pinned. +ISO_PATTERN = re.compile( + r'^(\d{4})-(\d{2})-(\d{2})([T ])(\d{2}):(\d{2}):(\d{2})' + r'(\.\d+)?(Z|[+-]\d{2}:?\d{2})?$') +DATE_PATTERN = re.compile(r'^\d{4}-\d{2}-\d{2}$') +STABLE_DATE = '2026-01-01' +STABLE_TIME = '00:00:00' +REQUEST_ID_KEYS = ('requestid', 'request_id', 'correlationid') +STABLE_REQUEST_ID = '00000000' + +EMAIL_PATTERN = re.compile(r'[^@\s]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}') +JWT_PATTERN = re.compile(r'\beyJ[A-Za-z0-9_-]{8,}') +HEX_PATTERN = re.compile(r'^[0-9a-fA-F]{32,}$') +# An opaque handle: long, no spaces, and mixing letters with digits. A sentence +# does not look like this and a slug is not this long. +# +# ':' and '/' are NOT in the class, deliberately. With them, every example URL +# in the suite ('http://localhost:5001/api/assets') matched and the examples lost +# the one string in them a reader most wants to see. A base64 token containing +# '/' therefore slips this rule - it is caught by its key instead, which is the +# reliable half of this anyway. +OPAQUE_PATTERN = re.compile(r'^(?=[^\s]*\d)(?=[^\s]*[A-Za-z])[A-Za-z0-9_.+=-]{24,}$') +# A credential riding in a URL's query string. This is the hole the key layer +# and the opaque layer BOTH miss by construction: the key is 'scripturl' or +# 'url', which names no secret, and OPAQUE_PATTERN excludes ':' and '/' so the +# surrounding URL never matches. A harvest published a real bootstrap token and +# a real kiosk setup code that way, in a file that is served on prod and copied +# to a wiki. The whole URL must not be dropped - it is the most useful string in +# the example - so only the parameter VALUE is scrubbed. +URL_CREDENTIAL_PATTERN = re.compile( + r'(?i)\b(t|token|code|key|apikey|api_key|secret|sig|signature|password|pw|' + r'auth|access_token|refresh_token)=([^&\s"\']+)') +IPV4_PATTERN = re.compile(r'\b(?:\d{1,3}\.){3}\d{1,3}\b') +UNC_PATTERN = re.compile(r'^\\\\[^\\]+\\') +# A path off the machine the harvest ran on. A pytest tmpdir is a different +# string on every run, and a developer's home directory is the exact material +# tests/test_docs_publishable.py exists to keep out of published pages. +LOCAL_PATH_PATTERN = re.compile(r'(^|\s)/(tmp|home|Users|var/folders)/|pytest-of-') + +# Addresses that name nothing: a loopback or a documentation host is safe to +# publish and is more useful in an example than a placeholder. +PUBLISHABLE_HOSTS = ('127.0.0.1', '0.0.0.0', 'localhost', 'example.com', + 'example.local', 'test.local') + +# How big an example may get. The spec is downloaded by every reader and parsed +# by every generated client, so a 400-row list response in one operation costs +# everybody. Three rows show the shape, which is the entire job of an example. +EXAMPLE_MAX_CHARS = 2000 +EXAMPLE_MAX_ITEMS = 3 +EXAMPLE_MAX_DEPTH = 8 +EXAMPLE_MAX_STRING = 200 + + +def _stable_timestamp(text): + """The same timestamp with its value pinned and its shape untouched. + + Fractional digits and the zone suffix are preserved exactly, because that is + the part a reader is reading it for - '2026-09-18T18:30:48.498252Z' and + '2026-09-18 18:30:48' are two different contracts. + """ + # A bare date too: a fixture that calls date.today() churns exactly like a + # timestamp does, and the shape is all an example was showing. + if DATE_PATTERN.match(text): + return STABLE_DATE + match = ISO_PATTERN.match(text) + if not match: + return None + fraction = '' + if match.group(8): + fraction = '.' + '0' * len(match.group(8)[1:]) + return (STABLE_DATE + match.group(4) + STABLE_TIME + fraction + + (match.group(9) or '')) + + +def _redacted_string(value): + """The marker for a string value that must not be published, or None. + + Returns None when the value is safe, so the caller can tell "checked and + fine" from "scrubbed". + """ + text = value.strip() + if not text: + return None + if EMAIL_PATTERN.search(text): + return '' + if JWT_PATTERN.search(text): + return '' + if UNC_PATTERN.match(text): + return '' + if LOCAL_PATH_PATTERN.search(text): + return '' + if HEX_PATTERN.match(text): + return '' + for found in IPV4_PATTERN.findall(text): + if found not in PUBLISHABLE_HOSTS: + return '' + if OPAQUE_PATTERN.match(text): + return '' + scrubbed = URL_CREDENTIAL_PATTERN.sub( + lambda match: '%s=' % match.group(1), text) + if scrubbed != text: + return scrubbed + return None + + +def redact(value, key='', depth=0): + """Scrub secrets, people and machines out of a harvested body. + + Key-driven first, value-driven second, and applied to every level - a token + two objects down is as published as one at the top. The marker names WHICH + class was matched, so a reader can see that the field exists and is not + simply empty, without learning what was in it. + + Deliberately conservative in the direction of over-redacting. A redacted + example is still a shape a client can copy; a published badge number cannot + be un-published. + """ + name = (key or '').lower() + if depth > EXAMPLE_MAX_DEPTH: + return '' + if isinstance(value, dict): + return {str(itemkey): redact(itemvalue, str(itemkey), depth + 1) + for itemkey, itemvalue in value.items()} + if isinstance(value, list): + # Only the first few rows survive, and the cut is recorded rather than + # silent: a reader who sees three assets should not conclude the list + # endpoint returns three. + trimmed = [redact(item, name, depth + 1) for item in value[:EXAMPLE_MAX_ITEMS]] + if len(value) > EXAMPLE_MAX_ITEMS: + trimmed.append('' + % (len(value) - EXAMPLE_MAX_ITEMS)) + return trimmed + # A NUMBER under a key ending in 'id' is a row identifier, not a credential. + # Without this, 'tokenid': 3 published as and the example + # for every token route lost the one field a caller needs to address the + # row. The exemption is deliberately narrow - numeric only, 'id' only, and + # it does not apply to the person or host rules below, where a badge number + # is a number and still nobody's business. + numericid = (isinstance(value, int) and not isinstance(value, bool) + and name.endswith('id')) + if name and not numericid and SECRET_KEY_PATTERN.search(name): + return '' + if name and PERSON_KEY_PATTERN.search(name): + return '' + if name and HOST_KEY_PATTERN.search(name): + return '' + if name in REQUEST_ID_KEYS: + return STABLE_REQUEST_ID + if isinstance(value, str): + marker = _redacted_string(value) + if marker: + return marker + pinned = _stable_timestamp(value) + if pinned is not None: + return pinned + if len(value) > EXAMPLE_MAX_STRING: + return value[:EXAMPLE_MAX_STRING] + '...' + return value + return value + + +def _example_fits(value): + """Whether a redacted example is small enough to publish.""" + try: + return len(json.dumps(value)) <= EXAMPLE_MAX_CHARS + except (TypeError, ValueError): + return False + + +def _best_example(samples): + """One example out of every sample recorded for an operation. + + Deterministic, because the suite runs in parallel and the order samples + arrive in is not stable: sort by size descending then by text, and take the + first that fits. Largest-that-fits is the most informative, and the text + tiebreak means two runs of the same suite produce the same spec - which is + what makes a regenerated docs/openapi.json reviewable as a diff. + """ + candidates = [] + for sample in samples: + scrubbed = redact(sample) + if not _example_fits(scrubbed): + continue + text = json.dumps(scrubbed, sort_keys=True) + candidates.append((-len(text), text, scrubbed)) + if not candidates: + return None + candidates.sort(key=lambda row: (row[0], row[1])) + return candidates[0][2] + + +# --------------------------------------------------------------------------- +# The pytest plugin half: loaded with `-p gen_openapi` by --harvest +# --------------------------------------------------------------------------- +# +# Flask.full_dispatch_request is patched rather than an after_request handler +# registered, because the app under test is built by the suite's own session +# fixture and there is no reliable moment to reach into it - the conftest +# imports create_app at module import, before any hook here could wrap it. +# Patching the class catches every app in the process however and whenever it +# was created. +# +# Recorded to one file per process, appended a line at a time: the suite runs +# under xdist, so several workers record at once, and a crash in one of them +# must not cost the others their samples. + +_HARVEST_STATE = {'original': None, 'path': None} + + +def _harvest_record(flaskrequest, response): + """Append one request/response transcript, if it is one worth keeping.""" + rule = getattr(flaskrequest, 'url_rule', None) + if rule is None or not rule.rule.startswith(API_PREFIX): + return + status = getattr(response, 'status_code', 0) + # A body that produced a 400 is an example of getting it wrong, and a 500 is + # an example of nothing. Only a call that worked describes the contract. + if status < 200 or status >= 300: + return + sent = None + try: + if flaskrequest.mimetype == 'application/json': + sent = flaskrequest.get_json(silent=True) + except Exception: + sent = None + got = None + try: + if (response.mimetype == 'application/json' + and not getattr(response, 'direct_passthrough', False) + and not getattr(response, 'is_streamed', False)): + got = json.loads(response.get_data(as_text=True)) + except Exception: + got = None + if sent is None and got is None: + return + line = json.dumps({ + 'method': flaskrequest.method, + 'rule': rule.rule, + 'request': sent, + 'response': got, + }) + try: + with open(_HARVEST_STATE['path'], 'a', encoding='utf-8') as handle: + handle.write(line + '\n') + except OSError: + pass + + +def pytest_configure(config): + """Wrap Flask's dispatch so every test-client call is transcribed. + + Inert unless --harvest set the directory, so loading this file as a plugin + in an ordinary run changes nothing. + """ + outdir = os.environ.get(HARVEST_DIR_VAR) + if not outdir or _HARVEST_STATE['original'] is not None: + return + import flask + original = flask.Flask.full_dispatch_request + _HARVEST_STATE['original'] = original + _HARVEST_STATE['path'] = os.path.join(outdir, 'samples-%d.jsonl' % os.getpid()) + + def dispatch(self): + response = original(self) + # A fault in the recorder must never change what the suite reports. The + # harvest is documentation; the tests are the product. + try: + _harvest_record(flask.request, response) + except Exception: + pass + return response + + flask.Flask.full_dispatch_request = dispatch + + +def pytest_unconfigure(config): + if _HARVEST_STATE['original'] is None: + return + import flask + flask.Flask.full_dispatch_request = _HARVEST_STATE['original'] + _HARVEST_STATE['original'] = None + + +def _read_samples(outdir): + """{(METHOD, rule): {'request': [...], 'response': [...]}} from a harvest run.""" + collected = {} + if not os.path.isdir(outdir): + return collected + for name in sorted(os.listdir(outdir)): + if not name.endswith('.jsonl'): + continue + with open(os.path.join(outdir, name), 'r', encoding='utf-8') as handle: + for line in handle: + line = line.strip() + if not line: + continue + try: + row = json.loads(line) + except ValueError: + continue + key = (row.get('method', '').upper(), row.get('rule', '')) + bucket = collected.setdefault(key, {'request': [], 'response': []}) + if row.get('request') is not None: + bucket['request'].append(row['request']) + if row.get('response') is not None: + bucket['response'].append(row['response']) + return collected + + +def fold_examples(collected): + """Write harvested examples into the inventory. Returns (request, response) counts. + + The inventory is the input to the generator, so this is where they belong - + it keeps the spec a pure function of the inventory, and it means a harvest + survives in the committed file for a reader who never runs the suite. + + ADDITIVE, deliberately. Only a route this run actually exercised is + rewritten; an entry the run never reached keeps the example it has. Two + reasons, and the second is the important one: + + A targeted harvest has to be targeted. `--harvest tests/test_core` would + otherwise strip the examples off every route those tests do not touch, + which is most of them - the narrow command would do the most damage. + + The suite does not exercise the same set twice. Run under xdist against a + shared instance directory, two full runs of the same tree reached 311 and + 327 operations. Clearing on absence turned that into a churn of examples + appearing and vanishing in a committed, published file, with nothing + wrong in the tree. + + An example that has gone stale is still a transcript of a response this app + really gave. A route that is gone entirely takes its entry with it, which + tests/test_api_inventory_parity.py already enforces. + """ with open(INVENTORY, 'r', encoding='utf-8') as handle: surfaces = json.load(handle) + requests = 0 + responses = 0 + for surface in surfaces: + for entry in surface.get('endpoints', []): + path = entry.get('path') or '' + sent = [] + got = [] + for method in re.split(r'[/,|]', entry.get('method') or 'GET'): + bucket = collected.get((method.strip().upper(), path)) + if bucket: + sent.extend(bucket['request']) + got.extend(bucket['response']) + example = _best_example(sent) + if example is not None: + entry['requestexample'] = example + example = _best_example(got) + if example is not None: + entry['responseexample'] = example + requests += 1 if 'requestexample' in entry else 0 + responses += 1 if 'responseexample' in entry else 0 + _write_inventory(surfaces) + return requests, responses + + +def harvest(pytestargs): + """Run the suite with the recorder attached, then fold what it saw in.""" + import subprocess + import tempfile + outdir = tempfile.mkdtemp(prefix='shopdb-openapi-harvest-') + environment = dict(os.environ) + environment[HARVEST_DIR_VAR] = outdir + # This file is the plugin. Putting scripts/ on the path is what makes + # `-p gen_openapi` resolvable, in the workers as well as the controller. + environment['PYTHONPATH'] = os.pathsep.join( + [HERE] + ([environment['PYTHONPATH']] if environment.get('PYTHONPATH') else [])) + command = [sys.executable, '-m', 'pytest', '-p', 'gen_openapi', '-q'] + command.extend(pytestargs or ['tests']) + print('harvesting examples: ' + ' '.join(command)) + # The suite's own exit status is not this command's: a red test still + # produced real transcripts for every route it did reach, and refusing to + # record them would make the documentation hostage to an unrelated failure. + subprocess.call(command, cwd=REPO, env=environment) + collected = _read_samples(outdir) + requests, responses = fold_examples(collected) + print('harvested %d operation(s); inventory now carries %d request ' + 'example(s) and %d response example(s)' + % (len(collected), requests, responses)) + + +EXAMPLE_FIELDS = ('requestexample', 'responseexample') + + +def _scrub_stored_examples(surfaces): + """Re-redact every example the inventory carries, before it is published.""" + for surface in surfaces: + for entry in surface.get('endpoints', []): + for field in EXAMPLE_FIELDS: + if field in entry and entry[field] is not None: + entry[field] = redact(entry[field], field) + return surfaces + + +def main(): + arguments = sys.argv[1:] + if '--refresh' in arguments: + refresh_inventory() + if '--harvest' in arguments: + # Everything after the flag is pytest's, so a targeted harvest is + # `--harvest tests/test_core/test_assets.py` and needs no second flag. + harvest(arguments[arguments.index('--harvest') + 1:]) + with open(INVENTORY, 'r', encoding='utf-8') as handle: + surfaces = json.load(handle) + # SCRUB ON THE WAY OUT AS WELL AS ON THE WAY IN. Harvested examples are + # stored in the inventory and a refresh preserves them, so a scrubber fixed + # after a harvest protects only future harvests - the stored copy keeps + # publishing whatever the old rules missed. On 2026-09-18 that was a live + # bootstrap token and a live kiosk setup code, both hidden in a URL. Running + # redaction here means the published file cannot carry a secret that the + # CURRENT rules would catch, whatever is sitting in the inventory. + surfaces = _scrub_stored_examples(surfaces) spec = build(surfaces) with open(OUT, 'w', encoding='utf-8') as handle: json.dump(spec, handle, indent=1) diff --git a/tests/test_api_inventory_parity.py b/tests/test_api_inventory_parity.py index f8637fc1..23df9351 100644 --- a/tests/test_api_inventory_parity.py +++ b/tests/test_api_inventory_parity.py @@ -183,3 +183,63 @@ def test_documented_auth_is_what_the_code_enforces(): 'inventory is derived, so fix the code or teach the classifier in ' 'scripts/gen_openapi.py, then re-run it with --refresh:\n %s' % (len(disagreements), '\n '.join(disagreements[:15]))) + + +# --------------------------------------------------------------------------- +# The third derived field: query parameters +# --------------------------------------------------------------------------- +# +# A Flask rule carries its path arguments and nothing else, so a route whose +# real interface is '?code=' or '?search=' documented no parameters at all - +# /api/usb/kiosk/setup among them, where '?code=' is the ONLY way to call it +# successfully. gen_openapi.py now reads them out of each view's AST and writes +# them into the inventory as `queryparams`. +# +# That field is DERIVED, like auth, and gated the same way and for the same +# reason: a refresh only rewrites, so without a comparison a hand-edit or a +# stale file publishes a query contract the handler does not implement. A +# parameter that is not really there is the worst kind of documentation defect, +# because a reader believes it, sends it, and is silently ignored. + + +def derived_queryparams(): + """{(METHOD, path): [parameter, ...]} as the sweep reads the code now.""" + generator = _generator() + app = create_app('testing') + derived = {} + for rule, methods, endpoint, view in generator._served_routes(app): + parameters = generator._query_parameters(view) + for method in methods: + derived[(method, normalise(rule))] = parameters + return derived + + +def documented_queryparams(): + """{(METHOD, path): [parameter, ...]} as the inventory has it committed.""" + documented = {} + for surface in json.loads(INVENTORY.read_text()): + for entry in surface.get('endpoints', []): + path = normalise(entry.get('path') or '') + for method in re.split(r'[/,|]', entry.get('method') or 'GET'): + method = method.strip().upper() + if method: + documented[(method, path)] = entry.get('queryparams') or [] + return documented + + +def test_documented_query_parameters_are_what_the_handler_reads(): + derived = derived_queryparams() + documented = documented_queryparams() + disagreements = [] + for key in sorted(set(derived) & set(documented)): + if derived[key] != documented[key]: + disagreements.append( + '%s %s\n documented: %s\n read: %s' + % (key[0], key[1], + [item['name'] for item in documented[key]], + [item['name'] for item in derived[key]])) + assert not disagreements, ( + '%d route(s) document query parameters that are not what the handler ' + 'reads. The field is derived, so regenerate with ' + 'scripts/gen_openapi.py --refresh:\n %s' + % (len(disagreements), '\n '.join(disagreements[:15]))) diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py new file mode 100644 index 00000000..c0e1eeb6 --- /dev/null +++ b/tests/test_openapi_examples.py @@ -0,0 +1,637 @@ +"""The two derived halves of the published spec: query parameters and examples. + +docs/openapi.json is served at /api/docs on production AND published to the +wiki, and it is what the MCP server builds its tools from. Two things were +missing from every operation in it, and both are now derived rather than +written: + + QUERY PARAMETERS. A Flask rule carries its path arguments and nothing else, + so 0 of 573 operations published a query parameter - including + /api/usb/kiosk/setup, where '?code=' is the only way to call it successfully. + scripts/gen_openapi.py now reads them out of each view's AST. + + EXAMPLES. 0 of 573 carried a machine-readable example. They are harvested + from the test suite, which already sends real bodies and asserts real + responses. + +Harvesting is where this module earns its place. A harvested body is whatever a +test happened to build, and tests are written with real-looking material - +passwords, tokens, badge numbers, hostnames, addresses. None of that matters in +a test file and all of it matters on a public page, so redaction runs before +anything reaches the spec. `redact` is tested here directly, and the generated +spec is swept for the same material, because a scrubber nobody checks is a +scrubber that stops working quietly. + +The other property tested here is that NOTHING IS INVENTED. A query argument +whose name the generator cannot resolve to a literal is not published at all: +an argument that is not really there is worse than a missing one, because a +reader believes it, sends it and is silently ignored. +""" + +import importlib.util +import json +import textwrap +from pathlib import Path + +import pytest +import re + +REPO = Path(__file__).resolve().parents[1] +SPEC = REPO / 'docs' / 'openapi.json' + + +def _generator(): + """scripts/gen_openapi.py, loaded by path. + + It is a script, not a package module. Loading it runs its imports and + nothing else - it builds no app and reads no database until it is asked to. + """ + path = REPO / 'scripts' / 'gen_openapi.py' + spec = importlib.util.spec_from_file_location('gen_openapi_examples', path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +@pytest.fixture(scope='module') +def generator(): + return _generator() + + +@pytest.fixture(scope='module') +def spec(): + if not SPEC.is_file(): + pytest.skip('no generated spec in this checkout') + return json.loads(SPEC.read_text()) + + +def operations(spec): + for path, item in spec['paths'].items(): + for verb, operation in item.items(): + yield path, verb, operation + + +def examples(spec): + """Every published example, as (where, value).""" + for path, verb, operation in operations(spec): + body = operation.get('requestBody') or {} + media = (body.get('content') or {}).get('application/json') or {} + if 'example' in media: + yield '%s %s request' % (verb.upper(), path), media['example'] + success = ((operation.get('responses') or {}).get('200') or {}) + media = (success.get('content') or {}).get('application/json') or {} + if 'example' in media: + yield '%s %s response' % (verb.upper(), path), media['example'] + + +# --------------------------------------------------------------------------- +# redact +# --------------------------------------------------------------------------- + + +def test_a_credential_is_redacted_by_its_key(generator): + """The key is the reliable signal, whatever the value happens to be today. + + A fixture that leaves passwordhash empty must not teach the scrubber that + passwordhash is safe. + """ + scrubbed = generator.redact({ + 'password': 'hunter2', + 'passwordhash': '', + 'apikey': 'abc', + 'refresh_token': 'abc', + 'X-API-Key': 'abc', + 'signature': 'abc', + }) + assert set(scrubbed.values()) == {''} + + +def test_a_person_and_a_machine_are_redacted_by_their_key(generator): + """Not secrets, and not ours to publish either. ADR-015 for the machine + half: one plant's server name is meaningless to every other site reading + these pages.""" + scrubbed = generator.redact({ + 'username': 'jsmith', + 'badge': '204411', + 'checkedoutby': 'J Smith', + 'hostname': 'WJSF0123', + 'fqdn': 'wjsf0123.example.net', + 'ipaddress': '10.4.2.19', + 'servicetag': 'H3K9QP2', + }) + assert scrubbed['username'] == '' + assert scrubbed['badge'] == '' + assert scrubbed['checkedoutby'] == '' + assert scrubbed['hostname'] == '' + assert scrubbed['fqdn'] == '' + assert scrubbed['ipaddress'] == '' + assert scrubbed['servicetag'] == '' + + +def test_a_credential_with_no_telling_key_is_redacted_by_its_value(generator): + """The half the key rules cannot reach: material in a free-text field, or + in a list, where nothing names it.""" + scrubbed = generator.redact({ + 'note': 'mail bob.smith@example.com when it lands', + 'detail': 'bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.aaaa.bbbb', + 'path': '\\\\fileserver\\deploy\\agent.msi', + 'where': 'reported from 10.11.12.13', + 'digest': 'd41d8cd98f00b204e9800998ecf8427e', + 'bag': ['carol@example.com'], + }) + assert scrubbed['note'] == '' + assert scrubbed['detail'] == '' + assert scrubbed['path'] == '' + assert scrubbed['where'] == '' + assert scrubbed['digest'] == '' + assert scrubbed['bag'] == [''] + + +def test_ordinary_material_survives(generator): + """Over-redaction has a cost too: an example scrubbed to nothing shows a + reader nothing. What is safe stays.""" + payload = { + 'assetnumber': 'A-10024', + 'model': 'Dell Latitude 5420', + 'isactive': True, + 'quantity': 12, + 'status': 'In Service', + 'url': 'http://localhost:5001/api/assets', + } + assert generator.redact(payload) == payload + + +def test_a_numeric_id_is_not_a_credential(generator): + """'tokenid': 3 is the row number, not the token. + + Redacting it cost every token route the one field a caller needs to address + the row. The exemption is numeric-only, so a string session id is still + scrubbed. + """ + scrubbed = generator.redact({'tokenid': 3, 'apikeyid': 7, + 'sessionid': 'a-long-opaque-string-value'}) + assert scrubbed['tokenid'] == 3 + assert scrubbed['apikeyid'] == 7 + assert scrubbed['sessionid'] == '' + + +def test_redaction_reaches_every_level(generator): + """A token two objects down is as published as one at the top.""" + scrubbed = generator.redact( + {'data': {'items': [{'inner': {'password': 'hunter2'}}]}}) + assert scrubbed['data']['items'][0]['inner']['password'] == '' + + +def test_redaction_is_idempotent(generator): + """A harvest runs again over a spec that already carries markers, and the + markers must not be re-scrubbed into something else.""" + once = generator.redact({'password': 'hunter2', 'model': 'Dell 5420'}) + assert generator.redact(once) == once + + +def test_a_long_list_is_trimmed_and_says_so(generator): + """Three rows show the shape, which is the whole job of an example - but a + reader must not conclude the endpoint returns three.""" + scrubbed = generator.redact({'data': list(range(50))}) + assert scrubbed['data'][:3] == [0, 1, 2] + assert 'more' in scrubbed['data'][-1] + + +def test_a_cyclic_depth_is_bounded(generator): + """Harvested bodies come from a running app, not from this file. A deeply + nested one must not take the generator down with it.""" + deep = current = {} + for _ in range(50): + current['child'] = {} + current = current['child'] + generator.redact(deep) + + +# --------------------------------------------------------------------------- +# The published spec, swept for the same material +# --------------------------------------------------------------------------- + + +# Patterns held HERE, deliberately not imported from the generator. A gate that +# checks the scrubber with the scrubber's own patterns can only ever assert that +# redact() ran: it was green while the spec published a live bootstrap token and +# a live kiosk setup code, because both hid in a URL whose key ('scripturl', +# 'url') names no secret and whose value the opaque rule excludes by design. +# These must keep catching that class even if someone edits the generator. +INDEPENDENT_URL_CREDENTIAL = re.compile( + r'(?i)[?&](t|token|code|key|apikey|api_key|secret|sig|signature|password|' + r'auth|access_token|refresh_token)=([^&\s"\'<]{8,})') +# Product token prefixes. If a new one is minted, add it here the same day. +INDEPENDENT_TOKEN_PREFIX = re.compile(r'\b(sdbb_|sdbe_|shopdb_pat_)[A-Za-z0-9_-]{8,}') + + +def _looks_high_entropy(text): + """A long mixed-case, digit-bearing run with no word structure. + + Deliberately crude: it is a backstop for a secret shape nobody has thought + of yet, not a classifier. Anything it flags is either a secret or an example + that would read better with a shorter value. + """ + for chunk in re.split(r'[\s"\'<>]+', text): + if len(chunk) < 28 or '.' in chunk or '/' in chunk: + continue + has = lambda pattern: re.search(pattern, chunk) + if has(r'[a-z]') and has(r'[A-Z]') and has(r'\d'): + return chunk + return None + + +def test_no_published_example_hides_a_credential_in_a_url(spec): + """The class the scrubber's own patterns cannot see. + + Two real credentials reached docs/openapi.json this way on 2026-09-18, in a + file served at /api/docs on production and copied to a published wiki. + """ + offenders = [] + for where, example in examples(spec): + blob = json.dumps(example) + found = INDEPENDENT_URL_CREDENTIAL.search(blob) + if found and not found.group(2).startswith(' generator.EXAMPLE_MAX_CHARS] + assert not offenders, '\n '.join(offenders[:15]) + + +def test_a_response_example_never_contradicts_the_schema_beside_it(spec): + """An example and a `$ref` that disagree are worse than no example at all. + + Nineteen routes here do not return the standard envelope and every one was + documented as if it did. A harvested transcript is evidence about which, + so the generator drops the envelope `$ref` on any operation whose real + response is a different shape. This is the gate on that: an operation + published with the envelope `$ref` and an example that is not an envelope + is the exact contradiction the harvest exists to remove. + """ + offenders = [] + for path, verb, operation in operations(spec): + media = (((operation.get('responses') or {}).get('200') or {}) + .get('content') or {}).get('application/json') or {} + if 'example' not in media: + continue + claims = 'SuccessEnvelope' in json.dumps(media.get('schema') or {}) + isenvelope = (isinstance(media['example'], dict) + and media['example'].get('status') == 'success') + if claims != isenvelope: + offenders.append('%s %s: schema says envelope=%s, example is=%s' + % (verb.upper(), path, claims, isenvelope)) + assert not offenders, '\n '.join(offenders[:15]) + + +# --------------------------------------------------------------------------- +# Derived query parameters: what is emitted, and what is deliberately not +# --------------------------------------------------------------------------- + + +def _derive(tmp_path, source): + """Run the generator's query sweep over one written-out module.""" + module = tmp_path / 'sample_views.py' + module.write_text(textwrap.dedent(source)) + return _generator()._query_index(str(module)) + + +def test_a_literal_query_read_is_emitted(tmp_path): + index = _derive(tmp_path, ''' + def view(): + search = request.args.get('search') + active = request.args.get('active', 'true') + days = request.args.get('days', 30, type=int) + tags = request.args.getlist('tag') + page = request.args['page'] + ''') + found = {item['name']: item for item in index['view']} + assert sorted(found) == ['active', 'days', 'page', 'search', 'tag'] + assert found['search'] == {'name': 'search', 'type': 'string', 'required': False} + assert found['active']['default'] == 'true' + assert found['days'] == {'name': 'days', 'type': 'integer', + 'required': False, 'default': 30} + assert found['tag']['type'] == 'array' + # request.args['x'] raises without the argument. It is the one read in the + # language that proves the caller must send it. + assert found['page']['required'] is True + + +def test_a_name_that_is_not_a_literal_is_not_published(tmp_path): + """The honesty rule, and the reason this is safe to derive at all. + + A key built at runtime cannot be resolved, and a parameter that is not + really there is worse than a missing one: a reader believes it, sends it, + and is silently ignored. A module-level constant DOES resolve, because it + is a literal with a name. + """ + index = _derive(tmp_path, ''' + TOKEN_ARG = 'bootstraptoken' + + def view(field): + built = request.args.get('filter_' + field) + indirect = request.args.get(field) + formatted = request.args.get(f'{field}id') + named = request.args.get(TOKEN_ARG) + ''') + assert [item['name'] for item in index['view']] == ['bootstraptoken'] + + +def test_the_repos_own_argument_helpers_are_read(tmp_path): + """get_pagination_params and intarg/intargs read arguments on a handler's + behalf, so a sweep that only looks for request.args misses the paging + contract of every list route in the product.""" + index = _derive(tmp_path, ''' + def view(): + page, perpage = get_pagination_params(request) + typeid = intarg('typeid') + since = intarg('days', 30) + rest = intargs('locationid', 'businessunitid') + ''') + found = {item['name']: item for item in index['view']} + assert sorted(found) == ['businessunitid', 'days', 'locationid', 'page', + 'per_page', 'perpage', 'typeid'] + assert found['page'] == {'name': 'page', 'type': 'integer', + 'required': False, 'default': 1} + assert found['days']['default'] == 30 + assert found['typeid']['type'] == 'integer' + + +def test_a_view_that_reads_nothing_publishes_nothing(tmp_path): + index = _derive(tmp_path, ''' + def view(asset_id): + return success_response({'assetid': asset_id}) + ''') + assert index['view'] == [] + + +# --------------------------------------------------------------------------- +# The generator without any of this +# --------------------------------------------------------------------------- + + +def test_a_spec_generates_with_no_harvest_and_no_query_parameters(generator): + """Both halves are OPTIONAL. A published checkout has no tests to harvest + from, and an inventory written before this existed has no `queryparams`. A + generator that needs either is a generator that cannot be run where it + matters.""" + built = generator.build([{ + 'surface': 'core-assets', + 'endpoints': [{ + 'method': 'GET|POST', + 'path': '/api/assets', + 'auth': 'permission:assets.view', + 'params': 'not documented', + 'purpose': 'List assets.', + 'example': 'curl http://localhost:5001/api/assets', + }], + }]) + operation = built['paths']['/api/assets']['get'] + assert 'parameters' not in operation + media = built['paths']['/api/assets']['post']['requestBody']['content'] + assert 'example' not in media['application/json'] + success = operation['responses']['200']['content']['application/json'] + assert 'example' not in success + assert success['schema'] == {'$ref': '#/components/schemas/SuccessEnvelope'} + + +def test_a_query_parameter_survives_into_the_spec(generator): + """The other direction: an inventory entry that has them publishes them.""" + built = generator.build([{ + 'surface': 'plugin-usb', + 'endpoints': [{ + 'method': 'GET', + 'path': '/api/usb/kiosk/setup', + 'auth': 'setup-code (single-use kiosk setup code in ?code=)', + 'params': 'not documented', + 'purpose': 'Trade a setup code for this browser kiosk cookie.', + 'example': 'curl http://localhost:5001/api/usb/kiosk/setup', + 'queryparams': [{'name': 'code', 'type': 'string', 'required': False}], + 'responseexample': {'status': 'success', 'data': None}, + }], + }]) + operation = built['paths']['/api/usb/kiosk/setup']['get'] + assert operation['parameters'] == [{ + 'name': 'code', 'in': 'query', 'required': False, + 'schema': {'type': 'string'}, + }] + success = operation['responses']['200']['content']['application/json'] + assert success['example'] == {'status': 'success', 'data': None} + # A query filter that matches nothing is an empty list and a 200. Only a + # path parameter can be a record that is not there. + assert '404' not in operation['responses'] + + +def test_a_per_request_value_is_pinned_but_keeps_its_shape(generator): + """A transcript carries the instant it was taken and the id of the request + that produced it, and both differ on every run. + + Published verbatim, re-harvesting rewrote 313 of 320 examples with no change + of meaning - an unreviewable diff over a committed, published file. An + example shows a reader the FORMAT of a field, not the moment one call + happened, so the format is kept exactly and the value is pinned. + """ + scrubbed = generator.redact({ + 'meta': {'timestamp': '2026-09-18T18:30:48.498252Z', + 'requestid': '859aa86b'}, + 'createddate': '2026-09-18 08:15:00', + 'expiresat': '2026-12-31T23:59:59+00:00', + 'installedon': '2026-09-18', + }) + # Microseconds, the space separator and the offset all survive: those are + # three different contracts and a reader is reading the example for which. + assert scrubbed['meta']['timestamp'] == '2026-01-01T00:00:00.000000Z' + assert scrubbed['meta']['requestid'] == '00000000' + assert scrubbed['createddate'] == '2026-01-01 00:00:00' + assert scrubbed['expiresat'] == '2026-01-01T00:00:00+00:00' + assert scrubbed['installedon'] == '2026-01-01' + + +def test_pinning_does_not_reach_ordinary_text(generator): + """Only a value that IS a timestamp. A model number that happens to contain + digits is not one.""" + payload = {'model': '5420-2026', 'note': 'due 2026-09-18 at the latest', + 'version': '1.2.3'} + assert generator.redact(payload) == payload + + +def test_a_local_path_is_not_published(generator): + """A path off the machine the harvest ran on says nothing to a reader and + is different on every run. A developer's home directory is also the exact + material tests/test_docs_publishable.py exists to keep off a public page.""" + scrubbed = generator.redact({ + 'shareroot': '/tmp/pytest-of-someone/pytest-240/test_roundtrip0', + 'checkout': '/home/someone/projects/shopdb-flask', + 'relative': 'deploy/windows/installer', + 'route': '/api/assets', + }) + assert scrubbed['shareroot'] == '' + assert scrubbed['checkout'] == '' + # A path that names no machine is the useful half, and it stays. + assert scrubbed['relative'] == 'deploy/windows/installer' + assert scrubbed['route'] == '/api/assets' + + +def test_a_harvest_adds_and_never_clears(generator, tmp_path): + """A targeted harvest has to be targeted. + + Clearing on absence meant `--harvest tests/test_core` stripped the examples + off every route those tests do not touch, which is most of them - the + narrow command would have done the most damage. It also made the committed + file churn for nothing: run under xdist against a shared instance + directory, two full runs of the same tree reached 311 and 327 operations. + """ + inventory = tmp_path / 'api-inventory.json' + inventory.write_text(json.dumps([{ + 'surface': 'core-assets', + 'endpoints': [ + {'method': 'GET', 'path': '/api/assets', + 'responseexample': {'status': 'success', 'data': ['kept']}}, + {'method': 'POST', 'path': '/api/assets'}, + ], + }])) + original = generator.INVENTORY + generator.INVENTORY = str(inventory) + try: + generator.fold_examples({ + ('POST', '/api/assets'): { + 'request': [{'assetnumber': 'A-1'}], + 'response': [{'status': 'success', 'data': {'assetid': 1}}], + }, + }) + finally: + generator.INVENTORY = original + entries = json.loads(inventory.read_text())[0]['endpoints'] + # Untouched by this harvest, and still carrying what it had. + assert entries[0]['responseexample'] == {'status': 'success', 'data': ['kept']} + assert entries[1]['requestexample'] == {'assetnumber': 'A-1'} + assert entries[1]['responseexample'] == {'status': 'success', + 'data': {'assetid': 1}} + + +def test_picking_one_example_out_of_many_is_deterministic(generator): + """The suite runs in parallel, so the order samples arrive in is not stable. + + Largest-that-fits with a text tiebreak means two runs over the same samples + produce the same spec, which is what makes a regenerated docs/openapi.json + reviewable as a diff instead of a rewrite. + """ + samples = [ + {'status': 'success', 'data': {'assetid': 1}}, + {'status': 'success', 'data': {'assetid': 2, 'assetnumber': 'A-2'}}, + {'status': 'success', 'data': None}, + ] + picked = generator._best_example(samples) + assert picked == generator._best_example(list(reversed(samples))) + assert picked['data']['assetnumber'] == 'A-2' + + +def test_an_example_that_cannot_be_made_to_fit_is_dropped(generator): + """Silence beats a truncated JSON document: half an object is not an + example of anything, and it is not what the route returned.""" + # A wide object, not a long string: strings and lists are already capped + # inside redact, so an object with hundreds of keys is the shape that can + # still come out over the limit. + huge = {'status': 'success', + 'data': {'field%03d' % index: 'value' for index in range(500)}} + assert generator._best_example([huge]) is None + # And a smaller sample of the same operation still wins, rather than the + # whole operation losing its example to one oversized transcript. + small = {'status': 'success', 'data': {'assetid': 1}} + assert generator._best_example([huge, small]) == small + + +def test_a_delete_that_reads_a_body_says_so(generator): + """DELETE /api/applications/{id} refuses without {"confirm": "OK"}. + + The generator declared a body for POST, PUT and PATCH only, so that route + published a call that cannot succeed and a client built from the spec fails + on the day. + + Evidence is the HANDLER reading a body (`readsbody`, derived from its AST), + not a harvested transcript. A transcript proves the test CLIENT sent + something, and the suite sends {} to routes that ignore it: on 2026-09-18 + transcript-only evidence published "this route reads a JSON body" on DELETE + /api/endpoints/agentkey, whose handler never calls get_json. Both halves are + pinned below. + """ + entries = [ + {'method': 'DELETE', 'path': '/api/applications/', + 'auth': 'permission:applications.delete', 'purpose': 'Delete it.', + 'readsbody': True, 'requestexample': {'confirm': 'OK'}}, + {'method': 'DELETE', 'path': '/api/assets/', + 'auth': 'permission:assets.delete', 'purpose': 'Delete it.'}, + # A transcript with no handler evidence: the suite sent a body, the + # route ignores it, so the contract must stay silent. + {'method': 'DELETE', 'path': '/api/endpoints/agentkey', + 'auth': 'permission:endpoints.manage', 'purpose': 'Revoke it.', + 'requestexample': {}}, + ] + built = generator.build([{'surface': 'core-applications', 'endpoints': entries}]) + withbody = built['paths']['/api/applications/{app_id}']['delete'] + media = withbody['requestBody']['content']['application/json'] + assert withbody['requestBody']['required'] is False + assert media['example'] == {'confirm': 'OK'} + # Transcript without handler evidence declares nothing. + ignored = built['paths']['/api/endpoints/agentkey']['delete'] + assert 'requestBody' not in ignored + assert 'requestBody' not in built['paths']['/api/assets/{assetid}']['delete'] diff --git a/tests/test_openapi_spec.py b/tests/test_openapi_spec.py index 45eb1570..8de1aa8a 100644 --- a/tests/test_openapi_spec.py +++ b/tests/test_openapi_spec.py @@ -189,3 +189,58 @@ def test_summaries_are_not_cut_mid_word(spec): if body and not body[-1].isalnum() and body[-1] not in ')]"\'': offenders.append('%s %s: %r' % (verb.upper(), path, summary[-40:])) assert not offenders, '\n '.join(offenders[:15]) + + +def test_every_parameter_is_well_formed(spec): + """A parameter with no name, no location or no schema is not a parameter. + + Query parameters are derived from each handler's AST now rather than left + out, which is 87 operations that could not be filtered, searched or paged + from this document before. Derived means a code change can produce a + malformed one, so the shape is checked here rather than assumed. + """ + offenders = [] + for path, verb, operation in operations(spec): + for parameter in operation.get('parameters', []): + where = '%s %s: %r' % (verb.upper(), path, parameter.get('name')) + if not parameter.get('name'): + offenders.append('%s %s: a parameter with no name' % (verb.upper(), path)) + if parameter.get('in') not in ('path', 'query', 'header', 'cookie'): + offenders.append(where + ' has no valid `in`') + if not isinstance(parameter.get('required'), bool): + offenders.append(where + ' does not say whether it is required') + if not parameter.get('schema'): + offenders.append(where + ' has no schema') + if parameter.get('in') == 'path' and not parameter.get('required'): + offenders.append(where + ' is in the path and optional, which ' + 'OpenAPI does not allow') + assert not offenders, '\n '.join(offenders[:15]) + + +def test_no_parameter_is_declared_twice(spec): + """(name, in) is the identity of a parameter. Two entries for one name is + ambiguous to a generated client, which picks one and drops the other.""" + offenders = [] + for path, verb, operation in operations(spec): + seen = set() + for parameter in operation.get('parameters', []): + key = (parameter.get('name'), parameter.get('in')) + if key in seen: + offenders.append('%s %s: %s in %s' + % (verb.upper(), path, key[0], key[1])) + seen.add(key) + assert not offenders, '\n '.join(offenders[:15]) + + +def test_a_query_parameter_is_not_the_path_argument_under_another_name(spec): + """`/api/assets/{assetid}?assetid=` is a contradiction: the same value in + two places, and a generated client has to guess which one the route reads.""" + offenders = [] + for path, verb, operation in operations(spec): + intemplate = set(re.findall(r'\{([^}]+)\}', path)) + query = {p['name'] for p in operation.get('parameters', []) + if p.get('in') == 'query'} + clash = sorted(intemplate & query) + if clash: + offenders.append('%s %s: %s' % (verb.upper(), path, clash)) + assert not offenders, '\n '.join(offenders[:15])