ITSM

Service Catalog

Catalog item definition, request fields, fulfillment workflow, approval chains, and the self-service portal.

Overview

The service catalog is the end-user-facing menu of IT services and products that employees can request. Each catalog item defines what can be requested, who can request it, what information to collect, and how to fulfill it. Requests are tracked as catalog request records with their own lifecycle.

Catalog Item Fields

FieldTypeRequiredDefaultDescription
idstring (cat_...)requiredautoUnique identifier.
namestringrequiredDisplay name shown in the catalog browser.
slugstringrequiredautoURL-safe identifier. Auto-derived from name.
descriptiontextoptionalFull description shown to requesters. Markdown supported.
shortDescriptionstringoptionalOne-line summary shown in catalog grid view.
categorystringoptionalGroups items in the catalog browser. Examples: Hardware, Software, Access, HR.
iconstringoptionalIcon name (Lucide icon slug) or URL to a custom icon image.
statusenumrequireddraftdraft · active · retired. Only active items appear in the catalog.
visibilityenumoptionalall_usersall_users · groups_only · hidden. Groups restrict to specific AD/IdP groups.
allowedGroupsstring[]optional[]If visibility=groups_only, list of group IDs that can see this item.
fulfillmentTypeenumrequiredworkflowworkflow · manual · automated. workflow runs a linked workflow on submission.
fulfillmentWorkflowstring (wf_...)optionalWorkflow triggered on request submission (when fulfillmentType=workflow).
approvalRequiredbooleanoptionalfalseIf true, request must be approved before fulfillment begins.
approversobjectoptional{}{ type: "manager"|"group"|"user", value: string }. Who must approve.
approvalTimeoutHoursintegeroptional48Auto-reject if approval not given within this many business hours.
slaHoursintegeroptionalTarget fulfillment time in business hours. Drives SLA tracking on requests.
formFieldsobject[]optional[]Dynamic form definition. See form field schema below.
costdecimaloptionalOptional display cost shown to requester. Informational only.
costCurrencystringoptionalUSDISO 4217 currency code.
tagsstring[]optional[]Search tags.
orderintegeroptional0Display order within category. Lower = higher.
pricedecimaloptional0Chargeback unit price for this item. See Catalog Cost Model below.
currencystringoptionalUSDISO 4217 currency code for price.
chargebackEnabledbooleanoptionalfalseIf true, requests for this item post cost to the requester’s cost center for chargeback reporting.
costCenterIdstring (ObjectId)optionalnullDefault cost center charged when this item is ordered.
pricingNotesstringoptionalnullFree-text note shown alongside price (e.g. billing cadence, proration rules).

Catalog Cost Model & Chargeback

Catalog items can carry a unit price/currency and an optional default costCenterId. When chargebackEnabled is true, submitted requests for that item are expected to carry cost through to the resulting Service Request via its totalCost/costCurrency fields (see Service Request Fulfillment Fields below), so spend can be attributed back to the requesting cost center.

Cost model fields are informational/billing metadata set on the catalog item and copied through to requests — FlowOS does not process payments. Chargeback reporting is driven by aggregating totalCost across Service Requests, as exposed by the Catalog Spend Analytics endpoint below.

Catalog Spend Analytics

Aggregates totalCost across Service Requests over a date range, for chargeback and budget reporting.

GET
/api/itsm/analytics/catalog-spend

Spend breakdown and top items for the given date range

FieldTypeRequiredDefaultDescription
fromquery param (ISO date)optional30 days agoStart of the reporting window.
toquery param (ISO date)optionalnowEnd of the reporting window.
groupByquery paramoptionalcatalogItemField to group the breakdown by, e.g. catalogItem, department, or month (buckets by createdAt as YYYY-MM).
json
// GET /api/itsm/analytics/catalog-spend?from=2026-06-01&to=2026-07-01&groupBy=month

{
  "success": true,
  "data": {
    "totalSpend": 48250,
    "totalRequests": 132,
    "avgCostPerRequest": 365.53,
    "currency": "USD",
    "breakdown": [
      { "key": "2026-06", "label": "2026-06", "totalCost": 48250, "requestCount": 132 }
    ],
    "topItems": [
      { "catalogItemId": "cat_laptop_request", "totalCost": 21000, "requestCount": 30 }
    ]
  }
}

Only requests with totalCost > 0 are included. breakdown is limited to the top 20 groups by cost; topItems is always grouped by catalogItemId and limited to the top 10.

Form Field Schema

Each item in formFields defines a question the requester must answer:

FieldTypeRequiredDefaultDescription
idstringrequiredUnique field key. Used as the key in the submitted request fields object.
typeenumrequiredtext · textarea · number · email · phone · date · select · multiselect · checkbox · radio · file_upload · table_lookup
labelstringrequiredDisplay label shown above the field.
placeholderstringoptionalPlaceholder text inside the field.
helpTextstringoptionalHint text shown below the field.
requiredbooleanoptionalWhether the field must be filled before submission.
optionsobject[]optional[{ value, label }] for select, multiselect, radio types.
tableLookupobjectoptional{ tableSlug, labelField, valueField, filters } for table_lookup type.
validationobjectoptional{ min, max, pattern, message } for numeric/text validation.
conditionsobject[]optionalShow/hide rules: [{ field, operator, value }]. Field appears only when condition is met.
orderintegeroptionalDisplay order within the form.

Catalog Request Fields

FieldTypeRequiredDefaultDescription
idstring (creq_...)requiredautoUnique identifier.
numberstringrequiredautoHuman-readable number (REQ-NNNN).
catalogItemIdstring (cat_...)requiredThe catalog item being requested.
requestedBystring (usr_...)requiredactorUser submitting the request.
requestedForstring (usr_...)optionalrequestedByUser the request is being made on behalf of (e.g. manager ordering for new hire).
statusenumrequiredsubmittedsubmitted · pending_approval · approved · rejected · fulfilling · fulfilled · cancelled
fieldsobjectrequired{}Key-value map of form field responses. Keys match catalog item formFields[].id.
approvalStatusenum (read-only)optionalnot_requirednot_required · pending · approved · rejected
approversobject[] (read-only)optionalcomputedApproval records generated from the catalog item approvers config.
workflowRunIdstring (run_...)optionalThe fulfillment workflow run ID. Set when fulfillment begins.
fulfillmentNotestextoptionalNotes from the fulfiller. Visible to the requester.
fulfilledAttimestampoptionalWhen status moved to fulfilled. Auto-set.
slaobjectoptionalcomputedSLA tracking object, same structure as incident SLA.
createdAttimestampoptionalautoSubmission timestamp.

Service Request Fulfillment Fields

Beyond the catalog-facing fields above, the underlying Service Request record (requests collection, shared with the rest of ITSM's task model) carries a set of fulfillment-tracking fields used once a request has been approved and handed off for delivery.

FieldTypeRequiredDefaultDescription
catalogItemIdstring (cat_...)optionalnullThe catalog item this request was submitted for.
fulfillmentWorkflowIdstring (ObjectId)optionalnullWorkflow Studio workflow run that is fulfilling this request.
provisionedAssetIdsstring[] (ObjectId)optional[]Install Base / asset records provisioned as a result of this request.
deliveryTeamIdstring (ObjectId)optionalnullGroup responsible for delivering/fulfilling the request.
expectedDeliverytimestampoptionalnullTarget delivery date, distinct from SLA due date.
actualDeliverytimestampoptionalnullWhen the request was actually delivered.
onBehalfOfstring (usr_...)optionalnullUser the request was placed for, when different from the requester (e.g. a manager ordering for a new hire).
businessJustificationtextoptionalnullRequester-supplied justification for the request.
departmentstringoptionalnullRequester’s department at time of submission.
costCenterstringoptionalnullCost center to charge for this request.
approvalChainIdstring (ObjectId)optionalnullApproval chain governing this request, if one applies.
orderNumberstringoptionalnullExternal order/PO number, when fulfillment involves procurement.
watcherIdsstring[] (usr_...)optional[]Users watching this request for updates.
escalatedAttimestampoptionalnullWhen the request was escalated.
escalatedIncidentIdsstring[] (inc_...)optional[]Incidents created as a result of escalating this request.
totalCostdecimaloptional0Total cost of this request, used by Catalog Spend Analytics.
costCurrencystringoptionalUSDISO 4217 currency code for totalCost.
notestextoptionalnullInternal fulfillment notes.
categorystringoptionalnullRequest category.
subcategorystringoptionalnullRequest subcategory.

App Builder Form Integration

Each catalog item can have a linked App Builder app that serves as its request form. This lets admins design rich, custom forms with full App Builder capabilities (conditional fields, data sources, custom layouts) instead of the default variable list.

Admin workflow

  • Open the catalog item in the builder at /itsm/catalog/builder/[id].
  • Go to the Form App tab.
  • Click "Create Form App" — a new App Builder app is created with a starter TSX form and the builder opens automatically.
  • Customise the form: add fields, change layout, wire a REST API data source, etc. The starter template already posts to /api/itsm/requests with the catalogItemId pre-filled.
  • Save in App Builder. The form is now live.

End-user experience

When a user opens the catalog item at /itsm/catalog/[id] and the item has a linked form app, the App Builder app is embedded as an iframe. The form submits directly to POST /api/itsm/requests and shows the resulting request number on success.

Catalog items without a form app continue to use the built-in variable-based form (backward compatible).

FieldTypeRequiredDefaultDescription
formAppIdstring (ObjectId)optionalnullID of the linked App Builder app. Set automatically by POST /api/itsm/catalog/:id/create-form-app. Can be unlinked via PATCH with formAppId: null.
POST
/api/itsm/catalog/:id/create-form-app

Create (or return existing) an App Builder app linked to this catalog item. Idempotent. Returns { appId, builderUrl }.

Workflow Trigger on Submission

Any workflow in Workflow Studio can be configured to fire automatically when a request is submitted. No per-item configuration is needed — the trigger is event-driven and applies globally.

Setup

  • Go to /workflows/new and create a workflow.
  • Set trigger type to Event.
  • Set event name to request.created.
  • Activate the workflow.

Every time a catalog request is submitted (via the built-in form or via the App Builder form app), the platform emits a request.created event. All active workflows matching that trigger fire automatically with the following payload:

json
{
  "requestId":     "...",
  "requestNumber": "REQ-0001",
  "catalogItemId": "...",
  "requestedBy":   "...",
  "workspaceId":   "...",
  "title":         "Request: Laptop for new hire",
  "variables": {
    "urgency":     "high",
    "seat_count":  250,
    "department":  "engineering"
  }
}

The variables key holds all form field responses submitted with the request. Access them in workflow nodes as ctx.payload.variables.fieldName.

Multiple workflows
You can have multiple workflows listening to request.created — all will fire. Use workflow conditions to filter by catalogItemId if you need item-specific logic.

API Quick Reference

GET
/api/itsm/catalog

List catalog items (respects visibility)

POST
/api/itsm/catalog

Create a catalog item (admin/developer)

GET
/api/itsm/catalog/:id

Get catalog item with form definition (includes formAppId)

PATCH
/api/itsm/catalog/:id

Update catalog item (accepts formAppId: null to unlink form app)

POST
/api/itsm/catalog/:id/create-form-app

Create or return existing App Builder form app linked to this item

POST
/api/itsm/requests

Submit a catalog request

GET
/api/itsm/requests

List requests (filtered by requester unless admin/manager)

GET
/api/itsm/requests/:id

Get request detail

PATCH
/api/itsm/requests/:id

Update a request, including status transitions

GET
/api/itsm/analytics/catalog-spend

Chargeback spend breakdown by catalog item, department, or month

Request approvals are not a catalog-specific endpoint — they run through the shared Approvals API (POST /api/approvals/:id/approve, POST /api/approvals/:id/reject) against approval records created with contextType: "request".

Example: Submit a request

bash
POST /api/itsm/requests
{
  "catalogItemId": "cat_laptop_request",
  "requestedFor": "usr_new_hire_bob",
  "fields": {
    "laptopModel":     "MacBook Pro 14 M4",
    "ramSize":         "32GB",
    "storageSize":     "1TB",
    "accessories":     ["magic_mouse", "usb_hub"],
    "deliveryAddress": "123 Main St, Floor 4, Desk 4B",
    "urgency":         "medium",
    "justification":   "New hire starting 2026-07-01"
  }
}