ConnectWise PSA Product Catalog
Overview
The ConnectWise Manage product catalog is the master list of everything an MSP sells — hardware SKUs, software licenses, managed service subscriptions, bundles, and service offerings. Catalog items are the building blocks that flow into quotes, opportunities, sales orders, agreement additions, and ticket charges. Getting the catalog right drives accurate quoting, consistent billing, and clean COGS/margin reporting.
This skill covers the full catalog item schema, the supporting lookup entities (categories, subcategories, manufacturers, product types, unit of measure), and the workflows for the most common MSP scenarios.
API Endpoints
Base: /procurement/catalog
Categories: /procurement/categories
Subcategories: /procurement/subCategories
Manufacturers: /procurement/manufacturers
Product types: /procurement/productTypes
Unit of measure: /procurement/unitOfMeasures
Product class: /procurement/productClasses
Available MCP tools (connectwise-manage-mcp):
| Tool | Purpose |
|---|---|
cw_search_catalog_items | Search catalog items with CW conditions syntax |
cw_get_catalog_item | Fetch one catalog item by ID |
cw_create_catalog_item | Create a new catalog item (common fields + extraFields passthrough) |
cw_update_catalog_item | JSON Patch update against an existing item |
cw_list_catalog_categories | List categories |
cw_list_catalog_subcategories | List subcategories (filter by category/id=N) |
cw_list_manufacturers | List manufacturers |
Product Class
productClass is the single most important field because it drives downstream billing, inventory, and agreement behavior.
| Class | Use For | Behavior |
|---|---|---|
NonInventory | Software licenses, pass-through charges, most SaaS | No stock tracking, cost = last-purchased or fixed |
Inventory | Physical hardware you stock | Tracks on-hand, reorder points, cost layers |
Bundle | Parent SKU composed of child SKUs | Expands into components at quote time |
Service | Labor-based services, project service items | Maps to work roles, billable on tickets |
Agreement | Recurring managed-services line items | Drives MRR additions on agreements |
Rule of thumb for MSPs:
- Per-endpoint managed services (RMM, EDR, backup) →
Agreement - M365 / Google Workspace licenses you resell →
NonInventory(orAgreementif billing monthly) - Switches, firewalls, desktops you physically hold →
Inventory - Project engineering hours, onboarding fee →
Service - "Small Business Bundle" that rolls up RMM + EDR + backup →
Bundle
Complete Catalog Item Field Reference
Core Identity
| Field | Type | Required | Description |
|---|---|---|---|
id | int | System | Auto-generated ID |
identifier | string(60) | Yes | Unique SKU / part number (your internal code) |
description | string(50) | Yes | Internal-facing short description |
customerDescription | string | No | Customer-facing description (shows on quotes/invoices) |
notes | string | No | Internal notes (not customer-visible) |
Classification
| Field | Type | Required | Description |
|---|---|---|---|
category | object | No | {id: categoryId} |
subcategory | object | Yes | {id: subcategoryId} — CW requires this |
type | object | Yes | {id: typeId} — product type |
productClass | enum | No | NonInventory / Inventory / Bundle / Service / Agreement |
serializedFlag | boolean | No | Track by serial number (hardware) |
serializedCostFlag | boolean | No | Per-unit cost tracking |
phaseProductFlag | boolean | No | Eligible as a project phase product |
Pricing & Cost
| Field | Type | Required | Description |
|---|---|---|---|
cost | decimal | No | Your cost |
price | decimal | No | Sell price |
priceMethodFlag | string | No | Markup_Flat, Markup_Percent, Gross_Margin, Price_Flat |
costFlag | string | No | Billable, DoNotBill, NoCharge |
taxableFlag | boolean | No | Subject to sales tax |
Vendor & Supply
| Field | Type | Required | Description |
|---|---|---|---|
manufacturer | object | No | {id: manufacturerId} |
manufacturerPartNumber | string | No | MPN (not your SKU — the mfr's part number) |
vendor | object | No | {id: vendorCompanyId} — a company flagged as a vendor |
vendorSku | string | No | Vendor's SKU for reordering |
Inventory
| Field | Type | Required | Description |
|---|---|---|---|
unitOfMeasure | object | No | {id: uomId} — Each, Box, Hour, Month, License, etc. |
minStockLevel | int | No | Reorder threshold |
ianCode | string | No | Inventory account number (GL) |
upc | string | No | UPC barcode |
Lifecycle
| Field | Type | Required | Description |
|---|---|---|---|
inactiveFlag | boolean | No | Retired from active sale |
specialOrderFlag | boolean | No | Not normally stocked |
buyingEveryFlag | boolean | No | Continuous purchase |
Passthrough Pattern: extraFields
The cw_create_catalog_item tool surfaces ~11 common fields directly as typed Zod params. For any field not in that list (e.g. manufacturerPartNumber, unitOfMeasure, upc, minStockLevel, serializedFlag), use extraFields:
{
"identifier": "DELL-OPTI-7010",
"description": "Dell OptiPlex 7010 Desktop",
"subcategoryId": 12,
"typeId": 3,
"cost": 849.00,
"price": 1199.00,
"categoryId": 5,
"manufacturerId": 17,
"productClass": "Inventory",
"taxableFlag": true,
"customerDescription": "Dell OptiPlex 7010 - i5/16GB/512GB SSD",
"extraFields": {
"manufacturerPartNumber": "OPT7010-i5-16-512",
"unitOfMeasure": { "id": 1 },
"vendor": { "id": 9823 },
"vendorSku": "DELL-7010-BSTOCK",
"minStockLevel": 2,
"serializedFlag": true,
"ianCode": "1400-INV-HW"
}
}
extraFields is merged into the POST body verbatim — anything the CW /procurement/catalog POST endpoint accepts will work.
Common MSP Recipes
Recipe 1: Hardware SKU (Inventory)
{
"identifier": "FW-MERAKI-MX67",
"description": "Meraki MX67 Firewall",
"subcategoryId": 8,
"typeId": 2,
"productClass": "Inventory",
"categoryId": 3,
"manufacturerId": 24,
"cost": 495.00,
"price": 795.00,
"taxableFlag": true,
"extraFields": {
"manufacturerPartNumber": "MX67-HW",
"unitOfMeasure": { "id": 1 },
"serializedFlag": true,
"minStockLevel": 1
}
}
Recipe 2: Software License / SaaS (NonInventory)
{
"identifier": "M365-BP",
"description": "M365 Business Premium",
"subcategoryId": 21,
"typeId": 5,
"productClass": "NonInventory",
"cost": 22.00,
"price": 28.50,
"taxableFlag": false,
"customerDescription": "Microsoft 365 Business Premium - per user/month",
"extraFields": {
"unitOfMeasure": { "id": 7 }
}
}
Recipe 3: Managed Service / MRR line item (Agreement)
{
"identifier": "MSP-WKST-MGD",
"description": "Managed Workstation",
"subcategoryId": 30,
"typeId": 9,
"productClass": "Agreement",
"cost": 18.00,
"price": 75.00,
"customerDescription": "Fully Managed Workstation - RMM, EDR, patching, backup",
"extraFields": {
"unitOfMeasure": { "id": 7 },
"ianCode": "4100-REC-MSP"
}
}
Recipe 4: Project Service / Labor (Service)
{
"identifier": "SVC-PM-HR",
"description": "Project Management - hourly",
"subcategoryId": 45,
"typeId": 11,
"productClass": "Service",
"cost": 85.00,
"price": 195.00,
"extraFields": {
"unitOfMeasure": { "id": 3 },
"phaseProductFlag": true
}
}
Updating Catalog Items (JSON Patch)
Use cw_update_catalog_item with JSON Patch ops. CW Manage is strict about patch syntax — reference fields use /id paths.