35 lines
1.6 KiB
Markdown
35 lines
1.6 KiB
Markdown
# 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
|
|
```
|