ConnectWise Manage Product Catalog

SkillAI & models

ConnectWise PSA product catalog: catalog items (SKUs), categories, subcategories, manufacturers, and their use on quotes, opportunities, agreements, and tickets. Covers the full catalog item field reference, common MSP workflows (hardware SKU, software license, managed service, agreement add-on), and the passthrough pattern for fields not surfaced on the MCP tool directly.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the ConnectWise Manage Product Catalog skill

What this skill tells your AI

The instructions your AI receives, as published by wyre-ai/msp-claude-plugins in msp-claude-plugins/connectwise/manage/skills/product-catalog/SKILL.md and read by ahel’s review.

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.

Anti-triggers

  • Pricing a deal for a customer — catalog items are the SKU master list; the priced, versioned document a customer actually receives is a ConnectWise CPQ quote. Use connectwise-cpq-quotes.
  • Line items on an existing quote — adding, repricing or removing a line happens on the quote, not the catalog; use connectwise-cpq-quote-items.
  • Another vendor's catalog — Autotask products and Kaseya Quote Manager SKUs share this vocabulary; use autotask-product-catalog or kaseya-quote-manager-quotes.

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):

ToolPurpose
cw_search_catalog_itemsSearch catalog items with CW conditions syntax
cw_get_catalog_itemFetch one catalog item by ID
cw_create_catalog_itemCreate a new catalog item (common fields + extraFields passthrough)
cw_update_catalog_itemJSON Patch update against an existing item
cw_list_catalog_categoriesList categories
cw_list_catalog_subcategoriesList subcategories (filter by category/id=N)
cw_list_manufacturersList manufacturers

Product Class

productClass is the single most important field because it drives downstream billing, inventory, and agreement behavior.

ClassUse ForBehavior
NonInventorySoftware licenses, pass-through charges, most SaaSNo stock tracking, cost = last-purchased or fixed
InventoryPhysical hardware you stockTracks on-hand, reorder points, cost layers
BundleParent SKU composed of child SKUsExpands into components at quote time
ServiceLabor-based services, project service itemsMaps to work roles, billable on tickets
AgreementRecurring managed-services line itemsDrives MRR additions on agreements

Rule of thumb for MSPs:

  • Per-endpoint managed services (RMM, EDR, backup) → Agreement
  • M365 / Google Workspace licenses you resell → NonInventory (or Agreement if 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

FieldTypeRequiredDescription
idintSystemAuto-generated ID
identifierstring(60)YesUnique SKU / part number (your internal code)
descriptionstring(50)YesInternal-facing short description
customerDescriptionstringNoCustomer-facing description (shows on quotes/invoices)
notesstringNoInternal notes (not customer-visible)

Classification

FieldTypeRequiredDescription
categoryobjectNo{id: categoryId}
subcategoryobjectYes{id: subcategoryId} — CW requires this
typeobjectYes{id: typeId} — product type
productClassenumNoNonInventory / Inventory / Bundle / Service / Agreement
serializedFlagbooleanNoTrack by serial number (hardware)
serializedCostFlagbooleanNoPer-unit cost tracking
phaseProductFlagbooleanNoEligible as a project phase product

Pricing & Cost

FieldTypeRequiredDescription
costdecimalNoYour cost
pricedecimalNoSell price
priceMethodFlagstringNoMarkup_Flat, Markup_Percent, Gross_Margin, Price_Flat
costFlagstringNoBillable, DoNotBill, NoCharge
taxableFlagbooleanNoSubject to sales tax

Vendor & Supply

FieldTypeRequiredDescription
manufacturerobjectNo{id: manufacturerId}
manufacturerPartNumberstringNoMPN (not your SKU — the mfr's part number)
vendorobjectNo{id: vendorCompanyId} — a company flagged as a vendor
vendorSkustringNoVendor's SKU for reordering

Inventory

FieldTypeRequiredDescription
unitOfMeasureobjectNo{id: uomId} — Each, Box, Hour, Month, License, etc.
minStockLevelintNoReorder threshold
ianCodestringNoInventory account number (GL)
upcstringNoUPC barcode

Lifecycle

FieldTypeRequiredDescription
inactiveFlagbooleanNoRetired from active sale
specialOrderFlagbooleanNoNot normally stocked
buyingEveryFlagbooleanNoContinuous 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.

Common patch patterns

Adjust price:

[{ "op": "replace", "path": "price", "value": 29.95 }]

Retire a SKU:

[{ "op": "replace", "path": "inactiveFlag", "value": true }]

Change manufacturer:

[{ "op": "replace", "path": "manufacturer/id", "value": 42 }]

Update customer description + cost atomically:

[
  { "op": "replace", "path": "customerDescription", "value": "M365 Business Premium (annual commit)" },
  { "op": "replace", "path": "cost", "value": 21.00 }
]

Search Patterns

Catalog search uses standard CW conditions syntax.

All active hardware from one manufacturer:

conditions=manufacturer/id=17 and inactiveFlag=false and productClass="Inventory"

SKUs with a specific prefix:

conditions=identifier like 'M365-%'

Items missing a manufacturer (data hygiene):

conditions=manufacturer=null and inactiveFlag=false

Price-list export — active NonInventory:

conditions=productClass="NonInventory" and inactiveFlag=false
orderBy=identifier asc

Recently updated:

conditions=_info/lastUpdated>=[2026-01-01T00:00:00Z]

Best Practices

  1. SKU conventions matter — pick a pattern (VENDOR-PRODUCT-VARIANT) and stick to it. Catalog bloat from inconsistent SKUs is the #1 reason CW quote selection gets painful.
  2. Always set productClass — default CW behavior when it's missing is rarely what MSPs want. Bundles and agreement items especially must be classified correctly or they won't expand / won't roll up MRR.
  3. subcategory and type are required — look them up first with cw_list_catalog_subcategories and cache the IDs. Don't hardcode.
  4. Separate description from customerDescription — internal SKU naming (short, searchable) vs customer-facing (descriptive, marketing-friendly).
  5. Retire, don't delete — set inactiveFlag=true instead of deleting. Historical quotes, tickets, and invoices reference the item by ID.
  6. Bundle children must exist first — create the component SKUs before the bundle parent, or the bundle creation will fail.
  7. GL account (ianCode) on agreement items — this is what flows to accounting. Missing ianCode on Agreement class items is a common source of bad financial reports.
  8. Keep cost current — margin reporting uses the catalog cost at quote time unless the quote has its own override. Stale cost = lying margin.

Pitfalls & Error Handling

SymptomCauseFix
SubCategory is requiredMissing subcategory.idInclude subcategoryId on create
Type is requiredMissing type.idInclude typeId on create
Duplicate identifierSKU already existsSearch first; or use cw_update_catalog_item
Bundle won't expand on quoteChild SKUs missing or productClass wrong on parentConfirm parent is productClass: "Bundle" and children exist
Agreement addition doesn't billproductClass is NonInventory instead of AgreementPatch productClass to Agreement
Price not applying on quotepriceMethodFlag overrides fixed priceSet priceMethodFlag: "Price_Flat" if you want the catalog price to stick
Serial prompt won't appearserializedFlag=falsePatch to true
Cost shows $0 on reportscost never set, relying on last-POSet an explicit cost value

Related Skills

Signals

GitHub stars
45
Forks
24
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
connectwise-manage-product-catalog
Source
github.com/wyre-ai/msp-claude-plugins