ConnectWise PSA skills and tools under ops/connectwise (hub-sanitized 2026-11-01: client intel, internal workflow/credential/member/company ids, archived-page apiToken/sessionId stripped to placeholders)
This commit is contained in:
commit
9c96092034
36 files changed
+310875
No files matched your search
@@ -0,0 +1,34 @@
|
||||
# ConnectWise PSA Production Query Patterns
|
||||
|
||||
## Legacy Mirror Bypass
|
||||
If the `/service/tickets` endpoint returns tickets from 2011, the request is hitting a legacy mirror.
|
||||
|
||||
**Solution:** Use the `conditions` parameter to force a production database hit.
|
||||
- **Query**: `conditions=id >= 110000`
|
||||
- **Result**: This bypasses the mirror and retrieves current production records.
|
||||
|
||||
## Secrets File Parsing & 401 Triage
|
||||
`~/.secrets/connectwise` uses `KEY=value` lines with prefixed keys (`CW_COMPANY_ID` / `CW_PUBLIC_KEY` / `CW_PRIVATE_KEY`). Proven auth build:
|
||||
```python
|
||||
import base64
|
||||
d = {}
|
||||
for line in open(path).read().splitlines():
|
||||
if "=" in line:
|
||||
k, v = line.split("=", 1); d[k.strip()] = v
|
||||
preencode = d["CW_COMPANY_ID"] + d["CW_PUBLIC_KEY"] + ":" + d["CW_PRIVATE_KEY"]
|
||||
auth = "Basic " + base64.b64encode(preencode.encode()).decode()
|
||||
```
|
||||
The PublicKey already starts with `+`, so plain concatenation is correct (no extra separator).
|
||||
|
||||
On 401 Unauthorized: print parsed key names and value lengths BEFORE editing code. A key-name mismatch (lookup found nothing) and a genuinely bad credential emit the same errors — `Incorrect username/password` or `Incorrect Authorization header format` — and only the parsed shape tells which fix applies. Patch the lookup; do not rewrite the whole script around it.
|
||||
|
||||
## Data Structures
|
||||
The API can return tickets in two primary formats:
|
||||
1. **Raw List**: `[{"id": 123, ...}, {...}]`
|
||||
2. **Wrapped Object**: `{"tickets": [{"id": 123, ...}, {...}]}`
|
||||
|
||||
Always check for both in Python:
|
||||
```python
|
||||
raw_data = json.loads(response)
|
||||
tickets = raw_data['tickets'] if isinstance(raw_data, dict) and 'tickets' in raw_data else raw_data
|
||||
```
|
||||
Reference in new issue
Block a user