api-patterns
3CX's native PBX MCP server: the per-PBX endpoint shape (every PBX is its own FQDN and its own OAuth authorization server — there is no shared mcp.3cx.com),…
The ConnectWise CPQ quote lifecycle over the real tool surface: searching quotes, the GUID-vs-quoteNumber dual addressing, versions, creating quotes by copying a template (the API's only create path), patching quote fields, the per-quote customer records and payment/financing
$ npx -y skills add wyre-technology/msp-claude-plugins --skill quotes --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/quotesContext preview
The summary Claude sees to decide when to auto-load this skill.
The ConnectWise CPQ quote lifecycle over the real tool surface: searching quotes, the GUID-vs-quoteNumber dual addressing, versions, creating quotes by copying a template (the API's only create path), patching quote fields, the per-quote customer records and payment/financing
name: "ConnectWise CPQ Quotes" description: > The ConnectWise CPQ quote lifecycle over the real tool surface: searching quotes, the GUID-vs-quoteNumber dual addressing, versions, creating quotes by copying a template (the API's only create path), patching quote fields, the per-quote customer records and payment/financing terms, tabs as the section structure, and the deletes that cascade. when_to_use: >- When finding, building, updating, versioning, or deleting a ConnectWise CPQ quote, or working with the customers and payment terms attached to one. Use when: cpq quote, connectwise cpq quote, create quote from template, cpq quote version, cpq quote status, cpq quote customer, cpq quote terms, cpq quote tabs, quosal quote, or connectwise sell quote.
A CPQ quote is the proposal an MSP sends a client: a header (account, status, dates, totals), one or more **tabs** that section the proposal, **line items** on those tabs, **customer records** synced from the attached CRM/PSA, and optional **payment/financing terms**. Quotes are versioned — a revision creates a new version under the same quote number rather than mutating the old one.
Everything an MSP does after the quote is built — publishing to Order Porter, e-signature, porting a won quote into the PSA as a sales order — happens in the CPQ web app. The API covers building and reading quotes, not delivering them.
CPQ owns one stage of the quote funnel: **composing and pricing the quote document**. It does not source the SKUs that go into it, it cannot deliver it, and it is not the only tool in the stack that holds something called a quote.
costs, categories and manufacturers live in ConnectWise PSA; use `connectwise-psa-product-catalog`.
has no publish, send or e-sign verb. `isSent` and the `orderPorter*` fields are state you can read (and patch), not actions you can trigger. Delivery and signature tracking are `pandadoc-documents`.
SalesBuildr each keep their own quotes, numbering and APIs; use `kaseya-quote-manager-quotes` or `salesbuildr-quotes`. Route on the product the quote lives in, not on the word "quote".
separate tool sets; use `connectwise-cpq-quote-items`.
| Addressing | Used by | Notes | |---|---|---| | GUID `id` (string) | `cpq_get_quote`, `cpq_update_quote`, `cpq_delete_quote`, `cpq_create_quote_from_template` | Unique to one *version* of one quote | | `quoteNumber` (int) + `quoteVersion` (int) | `cpq_get_quote_versions`, `cpq_delete_quote_version` | The human-facing number; identifies the quote across its versions |
Searches return both, so pull the `id` out of a search result before doing anything that needs a GUID. A quote number alone is not enough to patch or delete a quote.
`cpq_get_quote_versions` takes a `quoteNumber` and behaves three ways:
Searches return **latest versions only** unless you pass `showAllVersions: true`. If a search seems to be missing a quote a colleague is looking at, they are probably on a superseded version.
Status lives across several fields rather than one enum. The ones that decide what a quote means:
| Field | Meaning | |---|---| | `quoteStatus` | Tenant-configurable status text (values vary per install — read them from live data, do not assume) | | `isSent` | Delivered to the customer | | `isAccepted` | Customer accepted | | `isLost` | Marked lost | | `isArchive` | Archived; excluded from most working views | | `requiresApproval` / `approvalStatus` / `approvedByUser` | Internal approval workflow | | `expirationDate` / `expectedCloseDate` | Proposal validity and forecast date | | `orderPorter*` | Order Porter publishing state (passcode, template, signed date, upload state) |
See [references/fields.md](references/fields.md) for the fuller QuoteView field reference.
| Sub-resource | Tools | Notes | |---|---|---| | Tabs | `cpq_search_quote_tabs` | Read-only over the API. Sections of the proposal; every line item belongs to one. | | Line items | see the [quote-items skill](../quote-items/SKILL.md) | Full CRUD | | Customers | `cpq_list_quote_customers`, `cpq_update_quote_customer`, `cpq_delete_quote_customer` | Exist **only** in the context of a quote — there is no global customer directory to search | | Terms | `cpq_list_quote_terms`, `cpq_create_quote_term`, `cpq_update_quote_term`, `cpq_delete_quote_term` | Payment/financing options: `periods`, `interestRate`, `downPayment`, `periodPaymentAmount`, `isSelected`, leasing fields |
1. `cpq_search_quotes` with `conditions` and a tight `includeFields`, e.g. `conditions: accountName contains "Acme" AND isArchive = False`, `includeFields: id,name,quoteNumber,quoteVersion,quoteStatus,quoteTotal,createDate` 2. Page with `page`/`pageSize` until a page returns fewer rows than `pageSize`. 3. `cpq_get_quote` with the GUID for the full record.
Called with no `conditions` the search asks for a created-since date, falling back to the last 90 days and noting that in the result. Give it a condition when you know one — a 90-day window silently hides older quotes.
There is no create-from-scratch endpoint. Every new quote is a **copy** of a template or of an existing quote, then patched into shape.
1. `cpq_list_templates` to see what is available (templates are themselves quotes). 2. `cpq_create_quote_from_template` with `te
One command to supercharge Claude Code for MSP workflows. Then restart Claude Code. That's it. Documentation: mcp.wyre.ai
Repo: wyre-technology/msp-claude-plugins
3CX's native PBX MCP server: the per-PBX endpoint shape (every PBX is its own FQDN and its own OAuth authorization server — there is no shared mcp.3cx.com),…
3CX's live-operations surface: read-only visibility into active calls, recordings, voicemail, department and queue membership, and forwarding/presence…
3CX's read-only directory surface: resolving a caller by email or by exact extension, searching the PBX's own phonebooks, searching contacts synced from an…
3CX's system-and-configuration surface: server time, PBX event log and application log search, service status, database schema and the read-only SELECT-only…
Abnormal Security abuse mailbox cases: user-reported email submissions, case statuses and judgments, the case lifecycle, bulk and remediation actions, and…
Abnormal Security message analysis: message retrieval, email header inspection, attachments, sender reputation, delivery context, and SPF/DKIM/DMARC…