jaz-clio 5.47.2 → 5.47.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/skills/api/SKILL.md +4 -4
- package/assets/skills/api/references/endpoints.md +11 -14
- package/assets/skills/api/references/errors.md +8 -10
- package/assets/skills/api/references/field-map.md +2 -2
- package/assets/skills/api/references/full-api-surface.md +2 -2
- package/assets/skills/cli/SKILL.md +1 -1
- package/assets/skills/cli/references/command-catalog.md +16 -2
- package/assets/skills/conversion/SKILL.md +1 -1
- package/assets/skills/jaz-kit/SKILL.md +1 -1
- package/assets/skills/jaz-pseudo-sql/SKILL.md +1 -1
- package/assets/skills/jobs/SKILL.md +1 -1
- package/assets/skills/transaction-recipes/SKILL.md +1 -1
- package/cli.mjs +428 -428
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-api
|
|
3
|
-
version: 5.47.
|
|
3
|
+
version: 5.47.4
|
|
4
4
|
description: >-
|
|
5
5
|
Use this skill whenever you call, debug, or review code that touches the Jaz
|
|
6
6
|
REST API. Covers field names, response shapes, 159 production gotchas, error
|
|
@@ -129,9 +129,9 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
|
|
|
129
129
|
34. **Bookmarks use `items` array wrapper** with `name`, `value`, `categoryCode`, `datatypeCode`.
|
|
130
130
|
|
|
131
131
|
### Custom Fields
|
|
132
|
-
35. **
|
|
132
|
+
35. **Custom fields: `appliesTo` WORKS and `type` does nothing** (re-probed live 2026-09-02, reversing the previous entry). Send `appliesTo` as an OBJECT — `{invoices, bills, customerCredits, supplierCredits, payments}` sets the matching `applyTo*` to `SHOW`; **omit it and the field appears on nothing**. The old "do not send appliesTo" note came from an ARRAY example, which does 400. `format` is the ONLY control over the kind of field and the datatype is derived, not chosen: `CUSTOM` (default) yields `datatypeCode: TEXT`, any `ALL_*` value (`ALL_CUSTOMERS`/`ALL_SUPPLIERS`/`ALL_CONTACTS`/`ALL_EMPLOYEES`/`ALL_USERS`) yields `LIST`, a picklist of that population. **There is no NUMBER, DATE or DROPDOWN custom field**: `type`, `fieldType`, `entityType`, `datatypeCode` and `options` all return 200 and are silently dropped (an int on `datatypeCode` also returns 200, so the DTO does not declare it). `printOnDocuments` is required and not defaulted server-side.
|
|
133
133
|
35a. **Custom field values on transactions**: Set via `customFields: [{ customFieldName: "PO Number", actualValue: "PO-123" }]` on invoice/bill/customer-CN/supplier-CN/payment/item/fixed-asset create/update. NOT on journals, cash entries, or cash transfers. Read from GET responses in the same shape.
|
|
134
|
-
35b. **Custom field search**: `POST /custom-fields/search` with filter/sort/limit/offset. Filter by `customFieldName` (StringExpression), `datatypeCode` (StringExpression: TEXT,
|
|
134
|
+
35b. **Custom field search**: `POST /custom-fields/search` with filter/sort/limit/offset. Filter by `customFieldName` (StringExpression), `datatypeCode` (StringExpression: TEXT, LIST, DATE — there is no DROPDOWN; see rule 35).
|
|
135
135
|
35c. **Custom field GET**: `GET /custom-fields/:resourceId` returns full definition including `applyToSales`, `applyToPurchase`, `applyToCreditNote`, `applyToPayment`, `printOnDocuments`, `listOptions`.
|
|
136
136
|
|
|
137
137
|
### Tags on Transactions
|
|
@@ -171,7 +171,7 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
|
|
|
171
171
|
43. **Search sort is an object** — `{ sort: { sortBy: ["valueDate"], order: "DESC" } }`. Required when `offset` is present (even `offset: 0`).
|
|
172
172
|
44. **Bank records** — **Create**: Multipart CSV/OFX via `POST /magic/importBankStatementFromAttachment` or JSON via `POST /bank-records/:accountResourceId` with `{ records: [{amount, transactionDate, description?, payerOrPayee?, reference?}] }` (positive = cash-in, negative = cash-out, response: `{data: {errors: []}}`). **Search**: `POST /bank-records/:accountResourceId/search` — filter fields: `valueDate` (DateExpression), `status` (StringExpression: UNRECONCILED, RECONCILED, ARCHIVED, POSSIBLE_DUPLICATE), `description`, `extContactName` (payer/payee), `extReference`, `netAmount` (BigDecimalExpression), `extAccountNumber`. Sort by `valueDate` DESC default.
|
|
173
173
|
45. **Withholding tax** on bills/supplier CNs only. Retry pattern: if `WITHHOLDING_CODE_NOT_FOUND`, strip field and retry.
|
|
174
|
-
46. **Known API bugs (500s)**:
|
|
174
|
+
46. **Known API bugs (500s)**: capsules POST (upstream returns nil), catalogs POST, inventory balances by status GET (`/inventory-balances/:status`, missing `c.Bind`). **Contact groups PUT and custom fields PUT are NO LONGER on this list** — both were re-probed live 2026-09-02 and returned 200 and applied the change. Do not route around them.
|
|
175
175
|
47. **Non-existent endpoints**: `POST /inventory/adjustments` (and `/inventory-adjustments`, `/inventory-items/:id/adjustments`, `/items/:id/inventory-adjustments` — no stock-adjustment write path exists at any spelling), `GET /payments` (list), and `POST /payments/search` return 404 — these endpoints are not implemented. For payments, per-payment CRUD is `GET/PUT/DELETE /payments/:resourceId` and there ARE two payment-scoped searches — see Rule 64. `POST /deposits` also 404s, but for a different reason — see Rule 47a; do not read it as a missing feature.
|
|
176
176
|
47a. **Deposits are not an entity — the 404 on `/deposits` is by design.** A deposit is a **flag on a Chart of Accounts account**, not a document: the account carries `depositContactType` = `CUSTOMER` (advance received, a liability) or `SUPPLIER` (advance paid, an asset). Once flagged, a deposit movement is an **ordinary transaction against that account** — top up with `POST /journals` / `POST /cash-in-entries` / `POST /cash-out-entries` (one leg on the flagged account), draw down with `POST /invoices/:id/payments` or `POST /bills/:id/payments` passing `accountResourceId` = the flagged account **and `paymentMethod` set to something other than BANK_TRANSFER / CASH / CHEQUE** (use `OTHER`) — those three force a bank/cash account and 422 here, see Rule 80, read with `POST /cashflow-transactions/search`. **Flagging the account is a web-app action**: `depositContactType` is on no chart-of-accounts request or response model here, and the platform-backend mutation that sets it (`configureDepositAccounts`) is not proxied — so `POST /chart-of-accounts` cannot create a deposit account. Over the API you can only read and post against an account someone already flagged. Full walkthrough: `references/endpoints.md` → Deposits.
|
|
177
177
|
48. **Attachments — full CRUD**: **Add**: `POST /:type/:id/attachments` (multipart, `file` field, `application/pdf` or `image/*` — NOT `text/plain`). **List**: `GET /:type/:id/attachments`. **Delete**: `DELETE /:type/:id/attachments/:attachmentResourceId` (HTTP 200). CLI: `clio attachments add --file <path>` or `--url <url>`, `clio attachments list`, `clio attachments delete <attachmentResourceId>`. **Response shape is non-standard**: `{ reference, resourceId, attachments: [{fileName, fileType, fileId, attachmentResourceId}] }` — NOT `{ data: [...] }`. The attachment ID field is `attachmentResourceId` (not `resourceId`).
|
|
@@ -866,26 +866,23 @@ Always wrap in `{ payments: [...] }` even for single payment.
|
|
|
866
866
|
### POST /api/v1/custom-fields
|
|
867
867
|
|
|
868
868
|
```json
|
|
869
|
-
// Request (
|
|
870
|
-
{ "name": "PO Number", "
|
|
869
|
+
// Request (free-text field on invoices and bills):
|
|
870
|
+
{ "name": "PO Number", "printOnDocuments": false, "appliesTo": { "invoices": true, "bills": true } }
|
|
871
871
|
|
|
872
|
-
// Request (
|
|
873
|
-
{ "name": "
|
|
872
|
+
// Request (picklist of every customer):
|
|
873
|
+
{ "name": "Account Manager", "printOnDocuments": false, "format": "ALL_CUSTOMERS", "appliesTo": { "invoices": true } }
|
|
874
874
|
|
|
875
|
-
//
|
|
876
|
-
{ "name": "Delivery Date", "type": "DATE", "printOnDocuments": true }
|
|
877
|
-
|
|
878
|
-
// Response (includes both canonical and alias names):
|
|
875
|
+
// Response:
|
|
879
876
|
{ "data": { "customFieldName": "PO Number", "name": "PO Number", "status": "ACTIVE", "resourceId": "uuid" } }
|
|
880
877
|
```
|
|
881
878
|
|
|
882
|
-
**CRITICAL notes
|
|
879
|
+
**CRITICAL notes — re-probed live 2026-09-02, correcting several earlier entries**:
|
|
880
|
+
- **PUT works.** The 500 this file and SKILL.md rule 46 recorded is gone: a PUT returned 200 and applied the change. But it is a FULL REPLACE of `appliesTo` + `printOnDocuments`, and the GET returns `printOnDocuments` as null — the truth is in the `applyTo*` enum, where `PRINT` means it prints and `SHOW` means it does not. `updateCustomField` hydrates from that enum; a raw caller that omits `printOnDocuments` will silently turn printing off.
|
|
883
881
|
- POST uses `name`, GET returns both `customFieldName` and `name`
|
|
884
|
-
-
|
|
885
|
-
- `
|
|
886
|
-
-
|
|
887
|
-
-
|
|
888
|
-
- For DROPDOWN type, `options` array works (without `appliesTo`)
|
|
882
|
+
- `printOnDocuments` is REQUIRED and is not defaulted server-side — omitting it returns 422 `printOnDocuments is a required field` (recorded as a 400 before that). `create_custom_field` sends `false` when you omit it.
|
|
883
|
+
- **`appliesTo` WORKS and you should send it.** `{ invoices, bills, customerCredits, supplierCredits, payments }` sets the matching `applyTo*` response fields to `SHOW`. Omit it and every one stays `NULL`, i.e. the field appears on nothing. The previous "do NOT send appliesTo, causes Invalid request body" entry is wrong.
|
|
884
|
+
- **`format` is the only control over the KIND of field**, and the datatype is derived from it, not chosen: `CUSTOM` (default) yields `datatypeCode: TEXT`; any `ALL_*` value (`ALL_CUSTOMERS`, `ALL_SUPPLIERS`, `ALL_CONTACTS`, `ALL_EMPLOYEES`, `ALL_USERS`) yields `datatypeCode: LIST`, a picklist of that population.
|
|
885
|
+
- **There is no NUMBER, DATE or DROPDOWN custom field, and `type`/`fieldType`/`entityType`/`datatypeCode`/`options` are all silently dropped** — sent with a value, they return 200 and the field is created as plain TEXT. Verified by readback across five spellings; `datatypeCode: 12345` also returns 200, so the DTO does not declare it. `datatypeCode` on the response is derived and read-only; `format` is settable on POST **and** PUT (both verified 2026-09-02).
|
|
889
886
|
|
|
890
887
|
### GET /api/v1/custom-fields/:resourceId
|
|
891
888
|
|
|
@@ -95,20 +95,18 @@ Or call `list_account_classifications` — authoritative for that organisation.
|
|
|
95
95
|
**Fix**: Always include `printOnDocuments: false` (or `true`) in POST body. `create_custom_field` now sends `false` when you omit it, so this only bites a direct API caller.
|
|
96
96
|
**Note**: recorded here as a 400 "Invalid request body" until 2026-09-02, when a live probe returned `422 validation_error` with the field named. Either the API tightened or the original entry generalised from a different malformed body; the 422 is what it returns today.
|
|
97
97
|
```json
|
|
98
|
-
{ "name": "PO Number", "
|
|
98
|
+
{ "name": "PO Number", "printOnDocuments": false, "appliesTo": { "invoices": true } }
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
###
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
### WITHDRAWN — "do not send appliesTo" on custom fields
|
|
102
|
+
This entry said `appliesTo` caused "Invalid request body" and told callers to send `type` and `options` instead. Re-probed live 2026-09-02: the opposite is true.
|
|
103
|
+
- `appliesTo` as an OBJECT works — `{ "invoices": true, "bills": true }` returns 200 and sets `applyToSales`/`applyToPurchase` to `SHOW`. **Omitting it leaves every `applyTo*` at `NULL`, so the field appears on nothing.** The old entry's example sent an ARRAY (`["INVOICE"]`), which is the likely source of the original 400.
|
|
104
|
+
- `type`, `fieldType`, `entityType`, `datatypeCode` and `options` are all silently dropped: sent with a value they return 200 and the field is created as plain TEXT. There is no NUMBER/DATE/DROPDOWN custom field.
|
|
105
|
+
- `format` is the real control: `CUSTOM` (default) = free text, `ALL_*` = a picklist of that population.
|
|
104
106
|
```json
|
|
105
|
-
//
|
|
106
|
-
{ "name": "PO Number", "
|
|
107
|
-
|
|
108
|
-
// CORRECT:
|
|
109
|
-
{ "name": "PO Number", "type": "TEXT", "printOnDocuments": false }
|
|
107
|
+
// Correct:
|
|
108
|
+
{ "name": "PO Number", "printOnDocuments": false, "appliesTo": { "invoices": true, "bills": true } }
|
|
110
109
|
```
|
|
111
|
-
Valid `type` values: `"TEXT"`, `"DATE"`, `"DROPDOWN"` (UPPERCASE).
|
|
112
110
|
|
|
113
111
|
---
|
|
114
112
|
|
|
@@ -383,8 +383,8 @@ DELETE → expects "A" (parentEntityResourceId, via /cash-entries/:id)
|
|
|
383
383
|
| `name` (in GET response) | `customFieldName` | GET returns both `customFieldName` and `name` alias. |
|
|
384
384
|
| `name` (in POST body) | `name` | POST accepts `name`. |
|
|
385
385
|
| `showOnPdf` | `printOnDocuments` | Required boolean |
|
|
386
|
-
| `appliesTo` |
|
|
387
|
-
| `type`
|
|
386
|
+
| `appliesTo` | `appliesTo` (OBJECT) | `{invoices,bills,customerCredits,supplierCredits,payments,contacts,employeeClaims,fixedAssets,items,purchaseOrders,saleOrders}`. SEND IT — omit it and the field appears on nothing. An ARRAY 400s, which is what the old "do not send" note measured |
|
|
387
|
+
| `type` / `fieldType` / `entityType` | — (silently dropped) | Use `format`: CUSTOM = free text, ALL_* = a picklist. `datatypeCode` is derived (TEXT or LIST); there is no NUMBER/DATE/DROPDOWN field |
|
|
388
388
|
|
|
389
389
|
### Custom Field Values on Transactions
|
|
390
390
|
|
|
@@ -246,7 +246,7 @@ Body for all three: `{ items: [{btResourceId: "<uuid>", btType: "SALE|PURCHASE|S
|
|
|
246
246
|
| GET | `/contact-groups/:resourceId` | Get by ID |
|
|
247
247
|
| POST | `/contact-groups` | Create |
|
|
248
248
|
| POST | `/contact-groups/search` | Advanced search |
|
|
249
|
-
| PUT | `/contact-groups/:resourceId` | Update
|
|
249
|
+
| PUT | `/contact-groups/:resourceId` | Update — membership field is `associatedContactResourceIds`, not `contactResourceIds` |
|
|
250
250
|
| DELETE | `/contact-groups/:resourceId` | Delete |
|
|
251
251
|
|
|
252
252
|
### Items
|
|
@@ -293,7 +293,7 @@ Body for all three: `{ items: [{btResourceId: "<uuid>", btType: "SALE|PURCHASE|S
|
|
|
293
293
|
| GET | `/custom-fields/:resourceId` | Get by ID |
|
|
294
294
|
| POST | `/custom-fields` | Create |
|
|
295
295
|
| POST | `/custom-fields/search` | Advanced search |
|
|
296
|
-
| PUT | `/custom-fields/:resourceId` | Update
|
|
296
|
+
| PUT | `/custom-fields/:resourceId` | Update — full replace of `appliesTo`+`printOnDocuments`; omitting either resets it |
|
|
297
297
|
| DELETE | `/custom-fields/:resourceId` | Delete |
|
|
298
298
|
|
|
299
299
|
---
|
|
@@ -203,10 +203,24 @@ Same subcommands and flags as `cash-in`.
|
|
|
203
203
|
| `list` | `--limit`, `--offset`, `--all`, `--format`, `--json` |
|
|
204
204
|
| `get <id>` | `--json` |
|
|
205
205
|
| `search <query>` | `--limit`, `--offset` |
|
|
206
|
-
| `create` | `--name`, `--
|
|
206
|
+
| `create` | `--name`, `--description`, `--print-on-documents`, `--invoices`, `--bills`, `--customer-credits`, `--supplier-credits`, `--payments`, `--field-format` |
|
|
207
207
|
| `update <id>` | `--name` |
|
|
208
208
|
| `delete <id>` | |
|
|
209
209
|
|
|
210
|
+
`--field-format` picks the kind of field: `CUSTOM` (default) is free text; `ALL_CUSTOMERS` / `ALL_SUPPLIERS` / `ALL_CONTACTS` / `ALL_EMPLOYEES` / `ALL_USERS` make it a picklist of that population. The datatype is derived from it, not chosen — there is no NUMBER or DATE field. Send at least one applicability flag or the field appears on nothing.
|
|
211
|
+
|
|
212
|
+
### `clio catalogs` — Price catalogs
|
|
213
|
+
| Subcommand | Key flags |
|
|
214
|
+
|------------|-----------|
|
|
215
|
+
| `list` | `--limit`, `--offset`, `--all`, `--format`, `--json` |
|
|
216
|
+
| `search` | `--limit`, `--offset`, `--json` |
|
|
217
|
+
| `get <id>` | `--json` |
|
|
218
|
+
| `create` | `--name`, `--description`, `--status`, `--input`, `--json` |
|
|
219
|
+
| `update <id>` | `--name`, `--description`, `--status`, `--input`, `--json` |
|
|
220
|
+
| `delete <id>` | `--json` |
|
|
221
|
+
|
|
222
|
+
`update` is a FULL REPLACEMENT: pass `--input` with the complete body (get it first), because omitting `items` or `contactGroupResourceIds` drops them. `create` rejects a body with no items.
|
|
223
|
+
|
|
210
224
|
### `clio bookmarks` — Organization bookmarks
|
|
211
225
|
| Subcommand | Key flags |
|
|
212
226
|
|------------|-----------|
|
|
@@ -294,7 +308,7 @@ EmploymentType: `FULL_TIME` · `PART_TIME` · `CONTRACTOR` · `INTERN` · `TEMPO
|
|
|
294
308
|
### `clio bank` — Bank accounts and records
|
|
295
309
|
| Subcommand | Key flags |
|
|
296
310
|
|------------|-----------|
|
|
297
|
-
| `accounts` | `--limit`, `--
|
|
311
|
+
| `accounts` | `--limit`, `--json` |
|
|
298
312
|
| `get <id>` | `--json` |
|
|
299
313
|
| `records <accountId>` | `--from`, `--to`, `--status`, `--description`, `--limit`, `--offset`, `--all` |
|
|
300
314
|
| `add-records <accountId>` | `--input` (JSON array of bank records) |
|