# Agent Gotchas

> 19 critical gotchas for AI agents using the CLI. Learned from production testing.
> Violating these causes silent data errors or wasted API calls.

---

1. **Cash entries and transfers post ACTIVE and take no `--finalize`.** `clio cash-in`, `clio cash-out` and `clio cash-transfer` have no draft state at all (the API refuses `saveAsDraft: true` with a 422), so there is no flag to pass and nothing to finalize afterwards. Invoices, bills and journals are the ones the CLI saves as draft and `--finalize` posts.

2. **Line-item account resolution is NOT fuzzy.** The `accountResourceId` field inside `--lines` JSON arrays requires a UUID or exact account name. Fuzzy matching only works for top-level flags (`--contact`, `--account`). Always resolve accounts first: `clio accounts list --json | jq '.data[] | {name, id: .resourceId}'`.

3. **Create responses are minimal.** All create commands return only `{ "resourceId": "uuid" }`. To get the full entity (status, amounts, line items), run `clio <entity> get <id> --json` afterward.

4. **--offset is page number (0-indexed), not row skip count.** `--offset 0 --limit 100` = rows 1-100. `--offset 1 --limit 100` = rows 101-200. This is not the same as SQL OFFSET. Exceptions, where `--offset` is a ROW offset (next page = offset + limit): `purchase-items list/search`, `currency-rates list`, `claims payouts` and `reports generate general-ledger`. Each command's `--offset` help says which it is, and `--all` pages both kinds correctly.

5. **--all caps at 1,000 rows by default** (lowered from 10,000 in 2026-04). For large orgs, pass `--max-rows 50000` explicitly. The CLI auto-paginates with concurrent requests and **stops fetching once `--max-rows` is reached** (early-stop, not slice-after; the previous behavior would pull every page and discard the excess, causing minute-long hangs on busy sandboxes).

6. **Explicit --org wins over JAZ_API_KEY.** Use `--org oauth:<resourceId>` for OAuth or `--org <label>` for a saved key profile. Without `--org`, the environment key remains the default. Never print its value.

7. **--json output goes to stdout; errors go to stderr.** Piping `clio invoices list --json | jq .` works cleanly. Resolution feedback ("Contact: Acme Corp (abc1234...)") is on stderr and won't corrupt JSON. Always parse stdout only.

8. **Dates are YYYY-MM-DD in org-local timezone.** Not UTC, not epoch. The API stores dates without time component. `--date 2026-03-15` means March 15 in the org's configured timezone.

9. **Currency codes are uppercase ISO 4217.** `SGD`, `USD`, `EUR` -- not `sgd`, `usd`. Lowercase will be rejected by the API with a validation error.

10. **The `customer` and `supplier` fields on contacts are booleans.** `{ "customer": true, "supplier": false }` -- not strings. A contact can be both customer and supplier simultaneously.

11. **`clio schema` is for tool introspection, not data.** `clio schema --json` lists command groups and tool counts. `clio schema invoices --json` shows tool definitions. `clio schema invoices create --json` shows parameter schema. None of these hit the API.

12. **`clio jobs` is five working tools, not checklists.** `bank-recon match`, `payment-run outstanding`, `document-collection ingest`, `statutory-filing sg-cs` and `statutory-filing sg-ca`. No checklist commands exist (month-end, GST/VAT, audit prep and the rest are not commands): the job playbooks are reference docs in the jaz-jobs skill. `payment-run outstanding` and `ingest --upload` need auth; `match`, `sg-cs` and `sg-ca` run offline. Add `--json` for structured output.

13. **There is no recipe command: calculate, then post.** `clio calc <type> --json` returns the schedule and journal lines and posts nothing. To book it, create a capsule (`clio capsules create`) and post each step yourself (`journals` / `bills` / `invoices` / `cash-in` / `cash-out` `create`, with `capsuleResourceId` in the `--input` body). The calculator's account names are generic ("Cash / Bank Account"): map each to a real account before posting. `clio calc fx-reval` is verification only; never post its result.

14. **The `--input` flag reads JSON from a file.** For complex payloads (multi-line-item invoices, detailed journals), write JSON to a temp file and pass `--input payload.json` instead of long `--lines` flags with shell escaping issues. When `--input` is provided, all other body flags are ignored.

15. **`bills draft list` (also `invoices/customer-credit-notes/supplier-credit-notes draft list`) fans out one attachment lookup per draft** (5 in flight). On accounts with hundreds of drafts this hangs >30s by default. Pass `--max-rows 10` for spot checks. Long-term: a `--with-attachments` flag is on the roadmap.

16. **Bulk-upsert is TWO endpoints per entity for invoices/bills.** `clio invoices bulk-upsert` is FLAT (one line per row via `itemDescription` + `totalAmount` + `invoiceAccountResourceId` at row level). `clio invoices bulk-upsert-line-items` is NESTED (multi-line via `lineItems[]`). Sending `lineItems[]` to FLAT is silently ignored → $0 invoices. Match your data shape to the variant.

17. **Reconciliation `lineItems[]` use `name` + `organizationAccountResourceId`.** The `reconciliations invoice-receipt` and `reconciliations bill-receipt` payloads use a DIFFERENT line-item field naming than `bulk-upsert-line-items`. Recon-create uses `name` (description) + `organizationAccountResourceId` (revenue/expense account). Bulk uses `itemDescription` + `accountResourceId`. Don't copy-paste line-items between the two.

18. **`reconciliations invoice-receipt` / `bill-receipt` gate on `paymentDirection`, not BSE type.** The 422 error code "Invalid business transaction type" is misleadingly named; the actual API check is on the BSE's `paymentDirection`. **`invoice-receipt` requires `PAYIN`** (positive amount via `clio bank add-records` → `credit_amount > 0`). **`bill-receipt` requires `PAYOUT`** (NEGATIVE amount → `debit_amount > 0`). Statement-imported BSEs (`clio bank import`) also work; direction is set from the CSV. For programmatic seeding, `clio bank add-records` with the correct sign is sync, fast, and reliable; no need for the async magic-OCR `bank import` path.

19. **No universal/cross-entity search.** The previous `clio search <q>` (Typesense-backed grouped search) was removed; it was FE-typeahead infrastructure. For agent/programmatic search use the structured `--query` syntax on per-entity search commands (`clio invoices search --query "..."`, `clio bills search --query "..."`, etc.). See `references/search-syntax.md` (in api skill) for the full DSL: AND/OR/NOT, parentheses, amount ranges (`$500+`, `$100-500`), date ranges (`date:-30d`, `date:jan-mar 2025`), wildcards, and entity-specific fields.
