The Service Catalog turns ad-hoc "submit a ticket" requests into structured, routed, approval-aware service items. Each catalog item carries form schema + fulfillment profile + approval flag + owner team + ETA, so submissions become well-formed TaskerTasks the right team can act on immediately.
For end-user behavior, see Submitting Requests & Tracking Them.
The data model
- CatalogItem — name, description, icon, category, fulfillment profile, form schema (up to 30 fields), approval flag, ETA, owner team, default priority, active flag, popularity counter.
- CatalogCategory — hierarchical grouping (name, icon, parentId, sortOrder). Optional but recommended for browsability.
- Submission — becomes a TaskerTask bound to
profileId(the catalog item's fulfillment profile, defaultprofile-itil-service-request-{orgId}from §12by), withlinkedTaterEntityType='service-catalog',catalogItemId,catalogItemName, and a snapshot of the submitted form values incatalogFormValues.
Seeding the defaults
Run POST /api/service-catalog/seed-defaults (Admin) once per org. Idempotent — re-running upserts. Installs 5 starter categories (Hardware / Software & Applications / Access & Permissions / User Lifecycle / IT Support) and 8 starter items (Request New Laptop, Software Installation, Application Access Request, Password Reset, VPN Access, MFA Re-enrollment, New User Onboarding, User Off-boarding). All seeded items have isSystem: true — editable but not deletable.
From the app: Settings → Service Catalog → + Seed Defaults.
From MCP: there's no seed_defaults tool — call the REST endpoint directly or use the UI button.
Authoring custom catalog items
Use POST /api/service-catalog (Admin) with the schema documented in api/src/functions/serviceCatalog.ts. Key fields:
- name (≤200 chars), description (≤5000 chars), icon (emoji or short label)
- categoryId — links to a CatalogCategory
- fulfillmentProfileId — TaskerProfile id (defaults to the org's ITIL Service Request profile)
- formFields[] — up to 30 fields, each with
key(unique),label,type(text / textarea / select / date / number / email / user / checkbox),required,options[](for select),helpText,defaultValue,placeholder - approvalRequired — flag hint for the profile's status flow
- estimatedTimeMinutes — ETA shown in the listing
- ownerTeam — assignmentGroup default on the resulting task
- defaultPriority — Critical / High / Medium / Low
- isActive — deactivate without deleting (preserves history of past submissions)
Form field design tips
- Make required fields actually required. Use the
required: trueflag on every field the fulfilling team needs to start work. "Required" prevents users from submitting half-baked requests. - Use helpText to explain why you need the field. "Business Justification: explain the why so we can act faster" is much better than just "Business Justification".
- For select fields, write options the way users think. "Replacement laptop" beats "SKU REPLACE-STD-2024".
- For user-picker fields, use type: user. The form will validate email format and (in a future release) auto-suggest from your directory.
- Don't add fields you don't need. 8-10 well-chosen fields beat 20 catch-all fields. Form fatigue causes drop-off.
- Snapshot don't reference. Form values are denormalized onto the task at submission time. You can rename or remove a field later and old submissions still render correctly.
Managing categories
GET /api/service-catalog/categories— list all (sorted by sortOrder)POST /api/service-catalog/categories(Admin) — create or updateDELETE /api/service-catalog/categories/:id(Admin) — non-system only
Categories are hierarchical via parentId. Recommend a flat list of 5-7 top-level categories for browsability; sub-categorize only if any one has 8+ items.
Fulfillment routing
Submissions create TaskerTasks with:
profileId= catalog item'sfulfillmentProfileId(or the org's default ITIL Service Request profile)assignmentGroup= catalog item'sownerTeamcategory= catalog item'scategoryIdpriority= catalog item'sdefaultPriority
The TaskerProfile (§12by) drives the status workflow + SLA defaults. The ITIL Service Request profile has stages: Open → Approval Pending → In Progress → Fulfilled → Closed. If your item has approvalRequired: true, the workflow starts at Approval Pending.
Approval workflow design
Items marked approvalRequired: true require a human approver before fulfillment starts. The approver is:
- The submitter's direct manager (if known from Entra / org chart)
- A named approver on the catalog item's metadata (future)
- Otherwise, the catalog item's
ownerTeamlead
Approval happens via the Tasker task's status workflow — the approver opens the task, reviews the form values + justification, and transitions status from Approval Pending → In Progress (approve) or Approval Pending → Closed (reject, with a comment explaining why).
Popularity ranking
Every successful submission increments the catalog item's popularity counter (best-effort, non-fatal if it fails). The listing endpoint sorts by popularity desc → name. This surfaces top-requested items at the top so users find them fast. Reset to 0 on the item record if you need to manually de-rank an item.
MCP integration
Three MCP tools (HTTP + stdio parity):
list_service_catalog(Viewer+) — browse items, filter by categoryget_catalog_item(Viewer+) — read full form schema before submittingsubmit_catalog_request(Auditor+) — submit on behalf of a user; required-field validation enforced
Pattern for AI assistants: a user says "I need Salesforce access" → agent calls list_service_catalog to find the right item → get_catalog_item for the schema → asks user for required fields it doesn't know → submit_catalog_request. Every action audit-logged with via: 'mcp' or via: 'copilot' / via: 'claude'.
Pitfalls
- Seed TaskerProfiles before seeding ServiceCatalog. Catalog items reference
profile-itil-service-request-{orgId}by id. If the profile doesn't exist, submissions still work (the workflow is unconstrained) but you lose the status enforcement. Always seed profiles first per §12by. - System catalog items can't be deleted, only deactivated. Historical tasks reference
catalogItemIdand audit log shows the original name. UseisActive: falseto hide deprecated items without losing history. - Form fields with
type: selectmust have non-emptyoptions[]. The upsert handler rejects with a clear error. - Bulk-changing many catalog items? The popularity counter is a hot field. If you're scripting changes to lots of items, fetch latest before upsert to avoid clobbering recent submissions' popularity bumps.