syncro: Phase-1b breadth findings (leads/vendors/products/PO/worksheets)

Live-tested the remaining write resources on Howard Test. Recorded:
- wrapped response shapes (.lead.id/.vendor.id/.product.id/.purchase_order.id/
  .po_line_item.id/.worksheet_result.id) added to Verified Response Shapes.
- create_po_line_item requires product maintain_stock:true.
- worksheet templates live in GET /tickets/settings (.worksheet_templates[]), no standalone
  endpoint; need a valid worksheet_template_id.
- PUT /products requires name+description; leads/vendors/products/POs have NO DELETE (global
  test records persist -> GUI cleanup).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-10 16:46:22 -07:00
parent 555e1ffd5a
commit 1fa1a42092
2 changed files with 33 additions and 0 deletions

View File

@@ -590,6 +590,12 @@ Every endpoint's response shape, verified against the live API. Parse exactly as
| Create contract | POST `/contracts` | write OK but body does NOT echo the object | GET `/contracts` + match; never retry on null | | Create contract | POST `/contracts` | write OK but body does NOT echo the object | GET `/contracts` + match; never retry on null |
| Email invoice | POST `/invoices/{id}/email` | `{"message": "Email sent."}` | **200 even with NO recipient** — verify `customer.email` first | | Email invoice | POST `/invoices/{id}/email` | `{"message": "Email sent."}` | **200 even with NO recipient** — verify `customer.email` first |
| Email estimate | POST `/estimates/{id}/email` | `{"message": "Email sent"}` | **200 even with NO recipient** — verify `customer.email` first | | Email estimate | POST `/estimates/{id}/email` | `{"message": "Email sent"}` | **200 even with NO recipient** — verify `customer.email` first |
| Create lead | POST `/leads` | `{"lead": {...}}` | `.lead.id` |
| Create vendor | POST `/vendors` | `{"vendor": {...}}` | `.vendor.id` — no DELETE (persists) |
| Create/Update product | POST/PUT `/products/{id}` | `{"product": {...}}` | `.product.id` — `name`+`description` required; no DELETE |
| Create PO | POST `/purchase_orders` | `{"purchase_order": {...}}` | `.purchase_order.id` — no DELETE |
| Add PO line | POST `/purchase_orders/{id}/create_po_line_item` | `{"po_line_item": {...}}` | needs product `maintain_stock:true` |
| Create worksheet | POST `/tickets/{id}/worksheet_results` | `{"worksheet_result": {...}}` | `.worksheet_result.id` — template ids in `GET /tickets/settings` |
**Invoice GET line_items field names differ from ticket line_items:** `item` = product name, `name` = description, `price` = unit rate. Do not use `price_retail` when reading invoice line items. **Invoice GET line_items field names differ from ticket line_items:** `item` = product name, `name` = description, `price` = unit rate. Do not use `price_retail` when reading invoice line items.

View File

@@ -29,6 +29,33 @@ policy-folder objects). Host is `rmm.syncromsp.com` (Kabuto/RMM), separate from
- The token embeds an enrollment secret → it is a **credential**: vault it (per client), never - The token embeds an enrollment secret → it is a **credential**: vault it (per client), never
commit plaintext. `policy_folder_id` comes from `GET /policy_folders?customer_id=N`. commit plaintext. `policy_folder_id` comes from `GET /policy_folders?customer_id=N`.
## 2026-07-10 — Phase 1b (breadth: leads / vendors / products / PO / worksheets)
**Response shapes — these are all WRAPPED (unlike contacts/contracts):** `POST /leads` →
`{"lead":{...}}` (`.lead.id`); `POST /vendors` → `{"vendor":{...}}`; `POST`/`PUT /products` →
`{"product":{...}}`; `POST /purchase_orders` → `{"purchase_order":{...}}`;
`POST /purchase_orders/{id}/create_po_line_item` → `{"po_line_item":{...}}`;
`POST /tickets/{id}/worksheet_results` → `{"worksheet_result":{...}}`;
`DELETE .../worksheet_results/{id}` → `{"message":"N: We deleted <title>."}`.
**PO line items require the product to have `maintain_stock:true`.** `create_po_line_item`
against a non-stock product returns `{"errors":"...ensure that the item ... is set to
'Maintain Stock'."}`. Flip the product (`PUT /products/{id}` `maintain_stock:true`) first.
**Worksheet templates are NOT a standalone endpoint — they live in `GET /tickets/settings` →
`.worksheet_templates[]`** (`{id,title,account_id}`). You need a valid `worksheet_template_id`
to create a worksheet result (e.g. "Virus Removal" = 11341).
**`PUT /products/{id}` requires `name` AND `description`** (same as create) — 422 without.
**No DELETE endpoint for leads, vendors, products, purchase_orders** — test records in those
GLOBAL catalogs PERSIST (can't be removed via API; archive/hide in the GUI). Mark test items
`[TEST]` and set products `disabled:true`. Created this run (need GUI cleanup): lead 43492446,
vendor 809317, product 23639304 (disabled), PO 2101221 (+ line 8918508).
**Minor:** `POST /leads` `business_name` didn't persist (came back null); `first_name`/
`last_name`/`email`/`customer_id` did. Re-check the correct field for a lead's company name.
## 2026-07-10 — Phase 1 (PSA CRUD) ## 2026-07-10 — Phase 1 (PSA CRUD)
**Emailing an invoice/estimate returns 200 "Email sent" even when it delivered to NOBODY.** **Emailing an invoice/estimate returns 200 "Email sent" even when it delivered to NOBODY.**