Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Api Patterns

ASecurity

ConnectWise PSA REST API fundamentals: public/private key + clientId authentication, page/pageSize pagination, the conditions query syntax, rate limiting (60/min), and error-response handling.

48 stars
0 votes
0 copies
1 views
Added 10/2/2026
ai-agentsjavascriptjavadebuggingapidocumentation

Works with

cliapi

Security Analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned 10/2/2026

$npx -y skills add wyre-technology/msp-claude-plugins --skill api-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api Patterns?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Api Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wyre-technology-api-patterns-32d21b37/badge)](https://www.skillsdirectory.com/skills/wyre-technology-api-patterns-32d21b37)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: "ConnectWise Manage API Patterns"
description: >
  ConnectWise PSA REST API fundamentals: public/private key + clientId
  authentication, page/pageSize pagination, the conditions query syntax,
  rate limiting (60/min), and error-response handling.
when_to_use: >-
  When working with authentication using public/private keys and clientId, pagination with
  page/pageSize, conditions query syntax, rate limiting (60/min). Use when: connectwise api,
  connectwise authentication, connectwise auth, api conditions, query builder connectwise,
  connectwise pagination, api rate limit, connectwise rest, api error connectwise, public key
  private key, or client id connectwise.
---

# ConnectWise PSA API Patterns

## Overview

The ConnectWise PSA REST API provides access to all PSA entities including tickets, companies, contacts, projects, and time entries. This skill covers authentication, query syntax, pagination, rate limiting, and best practices for API integration.

## Anti-triggers

"ConnectWise" is an umbrella brand over three products with three
unrelated APIs. Loading the wrong one produces auth failures that read
like permission problems:

- **ConnectWise Automate** — on-premise RMM server, `/cwa/api/v1/` base
  path, Bearer-token auth, and singular `condition=` filters. PSA
  public/private keys will not authenticate against it. Use
  `connectwise-automate-api-patterns`.
- **ConnectWise CPQ (Sell/Quosal)** — its own host and credential set
  again; use `connectwise-cpq-api-patterns`.

## Base URLs

| Region | Base URL |
|--------|----------|
| North America | `https://api-na.myconnectwise.net/{codebase}/apis/3.0/` |
| Europe | `https://api-eu.myconnectwise.net/{codebase}/apis/3.0/` |
| Australia | `https://api-au.myconnectwise.net/{codebase}/apis/3.0/` |

Replace `{codebase}` with your company identifier (e.g., `v4_6_release` or custom).

### Legacy URLs

Some instances may use legacy URLs:
```
https://api-na.myconnectwise.net/v4_6_release/apis/3.0/
https://api-staging.connectwisedev.com/v4_6_release/apis/3.0/
```

## Authentication

### Public/Private Key + Client ID

ConnectWise PSA uses Basic Authentication with a combined credential string plus a Client ID header.

### Credential Format

```
Authorization: Basic base64({companyId}+{publicKey}:{privateKey})
clientId: {your-client-id}
```

### Step-by-Step Authentication

1. **Combine credentials:**
   ```
   companyId + "+" + publicKey + ":" + privateKey
   Example: company+publickey:privatekey
   ```

2. **Base64 encode:**
   ```
   base64("company+publickey:privatekey") = "Y29tcGFueStwdWJsaWNrZXk6cHJpdmF0ZWtleQ=="
   ```

3. **Set headers:**
   ```http
   Authorization: Basic Y29tcGFueStwdWJsaWNrZXk6cHJpdmF0ZWtleQ==
   clientId: your-registered-client-id
   Content-Type: application/json
   ```

### Example Request

```http
GET /v4_6_release/apis/3.0/service/tickets
Host: api-na.myconnectwise.net
Authorization: Basic Y29tcGFueStwdWJsaWNrZXk6cHJpdmF0ZWtleQ==
clientId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Content-Type: application/json
```

See [references/examples.md](references/examples.md) for a JavaScript authentication example and recommended environment variable setup.

### Obtaining Credentials

1. **API Member:** Create in System > Members > API Members
2. **Public/Private Keys:** Generate for API member
3. **Client ID:** Register at [ConnectWise Developer Portal](https://developer.connectwise.com/)

## Conditions Query Syntax

### Basic Syntax

```
conditions=field operator value
```

### Supported Operators

| Operator | Description | Example |
|----------|-------------|---------|
| `=` | Equals | `status/id=1` |
| `!=` | Not equals | `status/id!=5` |
| `<` | Less than | `priority/id<3` |
| `<=` | Less than or equal | `priority/id<=2` |
| `>` | Greater than | `dateEntered>2024-01-01` |
| `>=` | Greater than or equal | `dateEntered>=2024-01-01` |
| `contains` | Contains substring | `summary contains "email"` |
| `like` | Pattern match | `summary like "%email%"` |
| `in` | In list | `status/id in (1,2,3)` |
| `not in` | Not in list | `status/id not in (5)` |

### Field References

Use `/` to reference nested fields:

```
company/id=12345
status/name="New"
contact/firstName contains "John"
```

### Combining Conditions

**AND (default):**
```
conditions=company/id=12345 and status/id!=5 and priority/id<=2
```

**OR:**
```
conditions=status/id=1 or status/id=2
```

**Complex:**
```
conditions=(status/id=1 or status/id=2) and company/id=12345
```

### Date Conditions

**Date format:** `YYYY-MM-DD` or ISO 8601

```
conditions=dateEntered>=[2024-01-01]
conditions=dateEntered>=[2024-01-01T00:00:00Z] and dateEntered<[2024-02-01T00:00:00Z]
```

### String Conditions

**Exact match:**
```
conditions=summary="Email not working"
```

**Contains:**
```
conditions=summary contains "email"
```

**Like (wildcards):**
```
conditions=summary like "%email%"
conditions=company/identifier like "AC%"
```

### Null Checks

```
conditions=contact=null
conditions=assignedResource!=null
```

### URL Encoding

Special characters must be URL-encoded:

| Character | Encoded |
|-----------|---------|
| Space | `%20` |
| `=` | `%3D` |
| `<` | `%3C` |
| `>` | `%3E` |
| `"` | `%22` |

**Example:**
```
GET /service/tickets?conditions=company/id%3D12345%20and%20status/id!%3D5
```

## Pagination

### Request Parameters

| Parameter | Type | Default | Max | Description |
|-----------|------|---------|-----|-------------|
| `page` | int | 1 | - | Page number (1-based) |
| `pageSize` | int | 25 | 1000 | Records per page |

### Example Request

```http
GET /service/tickets?page=1&pageSize=100
```

### Response Headers

| Header | Description |
|--------|-------------|
| `Link` | Contains next/prev page URLs |
| `X-Total-Count` | Total record count (if requested) |

Paginate by incrementing `page` until the response has fewer records than
`pageSize`. See [references/examples.md](references/examples.md) for a
full fetch-all-pages implementation.

### Getting Total Count

```http
GET /service/tickets?conditions=status/id!=5&pageSize=1&fields=id
```

Check `X-Total-Count` header or use `/count` endpoint:

```http
GET /service/tickets/count?conditions=status/id!=5
```

## Rate Limiting

### Limits

| Limit | Value |
|-------|-------|
| Requests per minute | 60 |
| Per API member | Yes |

### Rate Limit Headers

| Header | Description |
|--------|-------------|
| `X-RateLimit-Limit` | Maximum requests per minute |
| `X-RateLimit-Remaining` | Requests remaining in window |
| `X-RateLimit-Reset` | Seconds until limit resets |

### 429 Response

When rate limited, you receive HTTP 429:

```json
{
  "code": "RateLimitExceeded",
  "message": "Rate limit exceeded. Try again in 30 seconds."
}
```

Implement exponential backoff with jitter on 429s using the `Retry-After`
header. See [references/examples.md](references/examples.md) for a retry
strategy implementation.

### Best Practices for Rate Limits

1. **Implement exponential backoff** - Don't hammer the API
2. **Check headers** - Monitor remaining requests
3. **Batch operations** - Reduce total requests
4. **Use webhooks** - Instead of polling for changes

## Error Handling

Errors return the relevant HTTP status code plus a JSON body with `code`
and `message` fields, and per-field detail in `errors[]`. See
[references/errors.md](references/errors.md) for the complete HTTP status
code table, error response format, and common error codes.

## Common API Patterns

### Field Selection

Request specific fields only:

```http
GET /service/tickets?fields=id,summary,status/name,company/name
```

### Ordering

```http
GET /service/tickets?orderBy=priority/id asc, dateEntered desc
```

### Child Collections

Include child records:

```http
GET /service/tickets?childconditions=notes/text contains "update"
```

### Custom Fields

```http
GET /service/tickets?customFieldConditions=customField1 contains "value"
```

## Webhook Configuration

ConnectWise can POST entity-change events to a registered callback URL.
See [references/webhooks.md](references/webhooks.md) for the callback
payload shape and the registration request.

## Best Practices

1. **Store credentials securely** - Never commit to source control
2. **Handle errors gracefully** - Retry transient failures
3. **Use pagination** - Don't fetch unbounded results
4. **Select needed fields** - Reduce payload size
5. **Log API calls** - For debugging and audit
6. **Monitor usage** - Track API call patterns

## API Documentation

- [ConnectWise Developer Portal](https://developer.connectwise.com/)
- [REST API Reference](https://developer.connectwise.com/Products/ConnectWise_PSA/REST)
- [API Schema Browser](https://developer.connectwise.com/Products/ConnectWise_PSA/REST#swagger)

## Related Skills

- [ConnectWise Tickets](../tickets/SKILL.md) - Ticket management
- [ConnectWise Companies](../companies/SKILL.md) - Company management
- [ConnectWise Contacts](../contacts/SKILL.md) - Contact management
- [ConnectWise Projects](../projects/SKILL.md) - Project management
- [ConnectWise Time Entries](../time-entries/SKILL.md) - Time tracking

Attribution

WYRE-AIWYRE-AI
View sourceSee grades on GitHubMore from wyre-technology →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698621 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →