jaz-clio 5.34.0 → 5.35.0
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/README.md +23 -0
- package/assets/skills/api/SKILL.md +7 -7
- package/assets/skills/api/references/endpoints.md +13 -13
- package/assets/skills/api/references/errors.md +19 -17
- package/assets/skills/api/references/feature-glossary.md +1 -1
- package/assets/skills/api/references/field-map.md +7 -7
- package/assets/skills/api/references/full-api-surface.md +7 -7
- package/assets/skills/cli/SKILL.md +1 -1
- package/assets/skills/cli/references/command-catalog.md +3 -4
- package/assets/skills/cli/references/common-workflows.md +5 -3
- package/assets/skills/conversion/SKILL.md +1 -1
- package/assets/skills/conversion/references/edge-cases.md +4 -4
- package/assets/skills/conversion/references/mapping-rules.md +4 -4
- package/assets/skills/conversion/references/option2-quick.md +3 -3
- package/assets/skills/conversion/references/verification.md +4 -4
- 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/jobs/references/month-end-close.md +3 -1
- package/assets/skills/transaction-recipes/SKILL.md +4 -2
- package/assets/skills/transaction-recipes/references/fx-revaluation.md +4 -3
- package/cli.mjs +516 -515
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,29 @@ clio invoices search --query 'status:unpaid AND $500+' # structured per-entity s
|
|
|
52
52
|
|
|
53
53
|
66 command groups, 16 report types, 13 calculators, 12 job playbooks. Every command takes `--json`. Run `clio --help` for the full list.
|
|
54
54
|
|
|
55
|
+
### Foreign currency
|
|
56
|
+
|
|
57
|
+
Rates read **base→source**: `1` unit of your organization's base currency `= N` units of the
|
|
58
|
+
foreign one. Whether that matches how the rate was quoted to you depends on which side your base
|
|
59
|
+
currency is on — an SGD-base org quoting "1 USD = 1.35 SGD" has it backwards and needs `0.74`, while
|
|
60
|
+
a USD-base org quoting "1 USD = 56.5 PHP" already has it right and sends `56.5` unchanged.
|
|
61
|
+
|
|
62
|
+
You do not have to flip it. Pass the number as you have it and say which way it reads:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# "1 USD = 1.35 SGD", from a bank statement, on an SGD-base org
|
|
66
|
+
clio invoices create --currency USD --exchange-rate 1.35 \
|
|
67
|
+
--rate-direction SOURCE_TO_FUNCTIONAL ...
|
|
68
|
+
|
|
69
|
+
# 0.74, straight out of clio currency-rates list
|
|
70
|
+
clio invoices create --currency USD --exchange-rate 0.74 ...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Omit `--exchange-rate` entirely to use the organization's stored rate, or the platform daily rate
|
|
74
|
+
when none is set. `clio calc fx-reval` requires `--rate-direction` explicitly — that calculator
|
|
75
|
+
takes rates in the opposite direction to the API, and guessing would silently change a number
|
|
76
|
+
that ends up in a journal.
|
|
77
|
+
|
|
55
78
|
## MCP server
|
|
56
79
|
|
|
57
80
|
358 tools for any AI agent that speaks MCP. Runs locally: no cloud, no ports.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-api
|
|
3
|
-
version: 5.
|
|
3
|
+
version: 5.35.0
|
|
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, 158 production gotchas, error
|
|
@@ -106,8 +106,8 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
|
|
|
106
106
|
|
|
107
107
|
### Journals & Cash
|
|
108
108
|
23. **Journals use `journalEntries`** with `amount` + `type: "DEBIT"|"CREDIT"` — NOT `debit`/`credit` number fields.
|
|
109
|
-
24. **Journals support multi-currency via `currency` object** — same format as invoices/bills: `"currency": { "sourceCurrency": "USD" }` (auto-fetch platform rate) or `"currency": { "sourceCurrency": "USD", "exchangeRate":
|
|
110
|
-
25. **`currency` object is the SAME everywhere** — invoices, bills, credit notes, AND journals all use `currency: { sourceCurrency: "USD", exchangeRate?: number }`. Never use `currencyCode: "USD"` (silently ignored on invoices/bills) or `currency: "USD"` (string — causes 400 on invoices/bills).
|
|
109
|
+
24. **Journals support multi-currency via `currency` object** — same format as invoices/bills: `"currency": { "sourceCurrency": "USD" }` (auto-fetch platform rate) or `"currency": { "sourceCurrency": "USD", "exchangeRate": 0.74 }` (custom rate). Must be enabled for the org. Omit for base currency. **Direction**: `exchangeRate` is functionalToSource (1 org-base unit = N `sourceCurrency`) — usually the inverse of a quoted rate. Pass your figure as-is with `rateDirection` rather than inverting by hand; Rule 49. Three restrictions apply to foreign currency journals: (a) **no controlled accounts** — accounts with `controlFlag` (AR, AP) are off-limits (use invoices/bills instead), (b) **no FX accounts** — FX Unrealized Gain/Loss/Rounding are system-managed, (c) **bank accounts must match** — can only post to bank accounts in the same currency as the journal (e.g., USD journal → USD bank account only, not SGD bank account). All other non-controlled accounts (expenses, revenue, assets, liabilities) are available.
|
|
110
|
+
25. **`currency` object is the SAME everywhere** — invoices, bills, credit notes, AND journals all use `currency: { sourceCurrency: "USD", exchangeRate?: number, rateDirection?: "FUNCTIONAL_TO_SOURCE" | "SOURCE_TO_FUNCTIONAL" }`. **Direction**: `exchangeRate` is functionalToSource (1 org-base unit = N `sourceCurrency`) — usually the inverse of a quoted rate. Pass your figure as-is with `rateDirection` rather than inverting by hand; Rule 49. Never use `currencyCode: "USD"` (silently ignored on invoices/bills) or `currency: "USD"` (string — causes 400 on invoices/bills).
|
|
111
111
|
26. **Cash entries use `accountResourceId`** at top level for the BANK account + `lines` array for offsets.
|
|
112
112
|
|
|
113
113
|
### Credit Notes & Refunds
|
|
@@ -164,8 +164,8 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
|
|
|
164
164
|
38. **All list/search endpoints use `limit`/`offset` pagination** — NOT `page`/`size`. **`offset` is a 0-indexed PAGE NUMBER, not a row-skip** (offset=1 = second page of `limit` rows). Default limit=100, offset=0. Max limit=1000, max offset=65536. `page`/`size` params are silently ignored. Response shape: `{ totalPages, totalElements, truncated, data: [...] }`. When `truncated: true`, a `_meta: { fetchedRows, maxRows }` field explains why (offset cap or `--max-rows` soft cap — default 10,000). Use `--max-rows <n>` to override. Always check `truncated` before assuming the full dataset was returned. **Payload tier (`view`) — page-then-drill:** `search_*` and the lean `list_*` tools (invoices, bills, contacts, items, journals, customer/supplier credit notes, sale/purchase orders) return a **compact summary row by default** (`view:"lean"` — id + reference/status/date/contact/amount). Search lean to FIND a record, then read it in full via its `get_*`; pass `view:"full"` only when you need whole rows up front (heavier — avoid for broad searches). Other collections always return full. CLI defaults to full; use `--view lean`.
|
|
165
165
|
|
|
166
166
|
### Other
|
|
167
|
-
39. **Currency rates use `/organization
|
|
168
|
-
40. **FX invoices/bills MUST use `currency` object** — `currencyCode: "USD"` (string) is **silently ignored** (transaction created in base currency!). Use `currency: { sourceCurrency: "USD" }` to auto-fetch platform rate (ECB/FRANKFURTER), or `currency: { sourceCurrency: "USD", exchangeRate:
|
|
167
|
+
39. **Currency rates use `/organization/currencies/:code/rates`** — enable currencies first via `POST /organization/currencies`, then set rates via `POST /organization/currencies/:code/rates` with body `{ "rate": 0.74, "rateApplicableFrom": "YYYY-MM-DD" }` (see Rule 49 for direction). The older hyphenated `/organization-currencies/...` rate paths still resolve but are marked **deprecated** in the OpenAPI spec — prefer the nested form. Cannot set rates for org base currency. Full CRUD: POST (create), GET (list), GET/:id, PUT/:id, DELETE/:id.
|
|
168
|
+
40. **FX invoices/bills MUST use `currency` object** — `currencyCode: "USD"` (string) is **silently ignored** (transaction created in base currency!). Use `currency: { sourceCurrency: "USD" }` to auto-fetch platform rate (ECB/FRANKFURTER), or `currency: { sourceCurrency: "USD", exchangeRate: 0.74 }` for a custom rate. Rate hierarchy: org rate → platform/ECB → transaction-level. **Direction**: `exchangeRate` is functionalToSource (1 org-base unit = N `sourceCurrency`) — usually the inverse of a quoted rate. Pass your figure as-is with `rateDirection` rather than inverting by hand; Rule 49.
|
|
169
169
|
41. **Invoice GET uses `organizationAccountResourceId`** for line item accounts — POST uses `accountResourceId`. Request-side aliases resolve `issueDate` → `valueDate`, `bankAccountResourceId` → `accountResourceId`, etc.
|
|
170
170
|
42. **Scheduler GET returns `interval`** — POST uses `repeat`. (Response-side asymmetry remains.)
|
|
171
171
|
43. **Search sort is an object** — `{ sort: { sortBy: ["valueDate"], order: "DESC" } }`. Required when `offset` is present (even `offset: 0`).
|
|
@@ -174,7 +174,7 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
|
|
|
174
174
|
46. **Known API bugs (500s)**: Contact groups PUT (nil pointer on search response), custom fields PUT (dangling stack pointers in mapping), capsules POST (upstream returns nil), catalogs POST, inventory balances by status GET (`/inventory-balances/:status`, missing `c.Bind`) — all return 500.
|
|
175
175
|
47. **Non-existent endpoints**: `POST /deposits`, `POST /inventory/adjustments`, `GET /payments` (list), and `POST /payments/search` return 404 — these endpoints are not implemented. To list/search payments, use `POST /cashflow-transactions/search` (the unified transaction ledger — see Rule 63).
|
|
176
176
|
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`).
|
|
177
|
-
49. **Currency rate direction: `rate` = functionalToSource (1 base = X foreign)** — POST `rate: 0.74` for a SGD org means 1 SGD = 0.74 USD. **If your data stores rates as "1 USD = 1.35 SGD" (sourceToFunctional), you MUST invert: `rate = 1 / 1.35 = 0.74`.** GET confirms both: `rateFunctionalToSource` (what you POSTed) and `rateSourceToFunctional` (the inverse).
|
|
177
|
+
49. **Currency rate direction: `rate` = functionalToSource (1 base = X foreign)** — POST `rate: 0.74` for a SGD org means 1 SGD = 0.74 USD. **If your data stores rates as "1 USD = 1.35 SGD" (sourceToFunctional), you MUST invert: `rate = 1 / 1.35 = 0.74`.** GET confirms both: `rateFunctionalToSource` (what you POSTed) and `rateSourceToFunctional` (the inverse). **You do not have to do the arithmetic**: `add_currency_rate`, `update_currency_rate` and the `currency` object on the 8 FX create tools (invoice, bill, journal, both credit notes, both cash entries, TTB) accept an optional `rateDirection` (`FUNCTIONAL_TO_SOURCE` | `SOURCE_TO_FUNCTIONAL`, the same enum `bulk_upsert_currency_rates` sends on the wire) — declare how your figure reads and pass it verbatim; the client inverts and strips the label, which is never transmitted. Prefer this to inverting by hand: a wrong inversion is silent and wrong by rate². `clio calc fx-reval` REQUIRES the direction — that calculator historically assumed the opposite convention to the API.
|
|
178
178
|
|
|
179
179
|
### Search & Filter
|
|
180
180
|
50. **Search endpoint universal pattern** — All 32 `POST /*/search` endpoints share identical structure: `{ filter?, sort: { sortBy: ["field"], order: "ASC"|"DESC" }, limit: 1-1000, offset: 0-65536 }`. `offset` is a 0-indexed page number (not row-skip). Sort is REQUIRED when offset is present (even `offset: 0`). Default limit: 100. `sortBy` is always an array on all endpoints (no exceptions). See `references/search-reference.md` for per-endpoint filter/sort fields.
|
|
@@ -532,7 +532,7 @@ When the user wants to OPEN, SEE, or SHARE something in the Jaz dashboard ("open
|
|
|
532
532
|
- **Bank records**: Create via JSON `POST /bank-records/:id` or multipart `POST /magic/importBankStatementFromAttachment`. Search via `POST /bank-records/:id/search` with filters (valueDate, status, description, extContactName, netAmount, extReference).
|
|
533
533
|
- **Scheduled invoices/bills**: Wrap as `{ status, startDate, endDate, repeat, invoice/bill: { reference, valueDate, dueDate, contactResourceId, lineItems, saveAsDraft: false } }`. `reference` is required.
|
|
534
534
|
- **Scheduled journals**: Flat: `{ status, startDate, endDate, repeat, valueDate, schedulerEntries, reference }`. `valueDate` is required.
|
|
535
|
-
- **FX currency (invoices, bills, credit notes, AND journals)**: `currency: { sourceCurrency: "USD" }` (auto-fetches platform rate) or `currency: { sourceCurrency: "USD", exchangeRate:
|
|
535
|
+
- **FX currency (invoices, bills, credit notes, AND journals)**: `currency: { sourceCurrency: "USD" }` (auto-fetches platform rate) or `currency: { sourceCurrency: "USD", exchangeRate: 0.74 }` (custom rate). Same object form on all transaction types. **Never use `currencyCode` string** — silently ignored.
|
|
536
536
|
|
|
537
537
|
158. **Match-to-EXISTING reconciliation — `reconcile_with_payments` / `reconcile_magic_match` / `reconcile_learned_prediction`.** These reconcile a bank entry against transactions/payments the org ALREADY has, vs `invoice_receipt`/`bill_receipt` which CREATE new ones. Prefer match-to-existing to avoid duplicates.
|
|
538
538
|
- **`reconcile_with_payments`** — the headline. `businessTransactionPayments[]` each carry an open bill/invoice's `cashflowTransactionResourceId` (from `search_cashflow_transactions` or a suggestion's `cftBtResourceId`) + `transactionAmount`; the endpoint CREATES the payment AND reconciles in one call — **no `pay_bill`/`pay_invoice` first.** Also accepts `matchedPayments[]` (existing payments) / `matchedBatchPayments[]` / `adjustment` (over/under-payment + FX write-off). Guard: ≥1 match array non-empty. **FX is auto-resolved server-side — pass NO `currencySettings`/rate for the common case.** Only the rare bill-currency ≠ bank-currency case needs explicit `paymentAmount` (bank ccy) + `currencySettings`. FX gain/loss is NOT auto-posted — post it via `adjustment.cashAdjustmentEntries[]` to an FX account. Errors: `PAYMENT_AMOUNT_REQUIRED_IN_BUSINESS_TRANSACTION_SOURCE_CURRENCY` (cross-ccy missing paymentAmount), `INVALID_EXCHANGE_RATE_ERROR` (adjustment leg in non-functional ccy missing rate), `TOTAL_RECONCILIATION_AMOUNT_MISMATCHED_WITH_STATEMENT_ENTRY_AMOUNT` (sum ≠ entry → add adjustment leg). **NOT idempotent, no client key — a blind retry double-creates a payment; re-check `search_bank_records(status:'RECONCILED')` before retry.**
|
|
@@ -289,11 +289,11 @@ Enable currencies first, then set rates via the **separate** rate endpoints belo
|
|
|
289
289
|
- To check before enabling: `GET /organization/currencies` and check if the code is already in the list.
|
|
290
290
|
- Sending an empty array `{ "currencies": [] }` returns 400.
|
|
291
291
|
|
|
292
|
-
### Currency Rates — `/organization
|
|
292
|
+
### Currency Rates — `/organization/currencies/:code/rates`
|
|
293
293
|
|
|
294
|
-
**
|
|
294
|
+
**Path note**: both enable and rates live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths still resolve but are marked **deprecated** in the OpenAPI spec — use the nested form.
|
|
295
295
|
|
|
296
|
-
#### POST /api/v1/organization
|
|
296
|
+
#### POST /api/v1/organization/currencies/:currencyCode/rates
|
|
297
297
|
|
|
298
298
|
```json
|
|
299
299
|
// Request:
|
|
@@ -304,16 +304,16 @@ Enable currencies first, then set rates via the **separate** rate endpoints belo
|
|
|
304
304
|
// HTTP 201
|
|
305
305
|
```
|
|
306
306
|
|
|
307
|
-
**CRITICAL**: Response `data` is a **plain string** `"Rate added successfully"` — NOT a CurrencyRate object. You do NOT get back a `resourceId`. If you need the rate's `resourceId` (e.g., for later PUT/DELETE), you must follow up with `GET /organization
|
|
307
|
+
**CRITICAL**: Response `data` is a **plain string** `"Rate added successfully"` — NOT a CurrencyRate object. You do NOT get back a `resourceId`. If you need the rate's `resourceId` (e.g., for later PUT/DELETE), you must follow up with `GET /organization/currencies/:code/rates` and match by `rateApplicableFrom` date.
|
|
308
308
|
|
|
309
309
|
**Required fields**:
|
|
310
|
-
- `rate` — positive number (must be > 0). Direction is **functionalToSource** (1 base = X foreign). Example for SGD org setting USD rate: `rate: 0.74` means 1 SGD = 0.74 USD. **If your data is sourceToFunctional (1 USD = 1.35 SGD), invert: `rate = 1 / yourRate`.**
|
|
310
|
+
- `rate` — positive number (must be > 0). Direction is **functionalToSource** (1 base = X foreign). Example for SGD org setting USD rate: `rate: 0.74` means 1 SGD = 0.74 USD. **If your data is sourceToFunctional (1 USD = 1.35 SGD), invert: `rate = 1 / yourRate`.** You do not have to do this by hand: pass your figure as-is with `rateDirection` (`FUNCTIONAL_TO_SOURCE` | `SOURCE_TO_FUNCTIONAL`) and the client inverts and strips it. See SKILL.md Rule 49.
|
|
311
311
|
- `rateApplicableFrom` — `YYYY-MM-DD` string (NOT ISO datetime — `"2026-02-10T00:00:00Z"` is rejected with "does not match 2006-01-02 format")
|
|
312
312
|
|
|
313
313
|
**Optional fields**:
|
|
314
314
|
- `rateApplicableTo` — `YYYY-MM-DD` string. Must be after `rateApplicableFrom` (422 `INVALID_DATE_RANGE` otherwise).
|
|
315
315
|
|
|
316
|
-
#### GET /api/v1/organization
|
|
316
|
+
#### GET /api/v1/organization/currencies/:currencyCode/rates
|
|
317
317
|
|
|
318
318
|
```json
|
|
319
319
|
// Response:
|
|
@@ -335,7 +335,7 @@ Enable currencies first, then set rates via the **separate** rate endpoints belo
|
|
|
335
335
|
}
|
|
336
336
|
```
|
|
337
337
|
|
|
338
|
-
#### PUT /api/v1/organization
|
|
338
|
+
#### PUT /api/v1/organization/currencies/:currencyCode/rates/:resourceId
|
|
339
339
|
|
|
340
340
|
```json
|
|
341
341
|
// Request:
|
|
@@ -346,7 +346,7 @@ Enable currencies first, then set rates via the **separate** rate endpoints belo
|
|
|
346
346
|
// HTTP 200
|
|
347
347
|
```
|
|
348
348
|
|
|
349
|
-
#### DELETE /api/v1/organization
|
|
349
|
+
#### DELETE /api/v1/organization/currencies/:currencyCode/rates/:resourceId
|
|
350
350
|
|
|
351
351
|
```json
|
|
352
352
|
// Response:
|
|
@@ -371,12 +371,12 @@ Create exchange rates in bulk (max 500). **Auto-enables currencies not yet enabl
|
|
|
371
371
|
{
|
|
372
372
|
"sourceCurrencyCode": "USD",
|
|
373
373
|
"rate": 1.35,
|
|
374
|
-
"rateDirection": "
|
|
374
|
+
"rateDirection": "SOURCE_TO_FUNCTIONAL",
|
|
375
375
|
"rateApplicableFrom": "2026-03-29"
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
378
|
"sourceCurrencyCode": "EUR",
|
|
379
|
-
"rate":
|
|
379
|
+
"rate": 0.68,
|
|
380
380
|
"rateDirection": "FUNCTIONAL_TO_SOURCE",
|
|
381
381
|
"rateApplicableFrom": "2026-03-29",
|
|
382
382
|
"rateApplicableTo": "2026-04-30"
|
|
@@ -388,7 +388,7 @@ Create exchange rates in bulk (max 500). **Auto-enables currencies not yet enabl
|
|
|
388
388
|
{ "data": { "resourceId": null, "resourceIds": ["uuid1", "uuid2"] } }
|
|
389
389
|
```
|
|
390
390
|
|
|
391
|
-
`rateDirection
|
|
391
|
+
`rateDirection` (SGD-base org, USD source): `FUNCTIONAL_TO_SOURCE` means the value is source-per-base — 1 SGD = 0.74 USD → send `0.74`. `SOURCE_TO_FUNCTIONAL` means base-per-source — 1 USD = 1.35 SGD → send `1.35` as-is, no inversion. This is the ONLY rate endpoint that accepts the everyday quote directly; the single-rate POST always wants `FUNCTIONAL_TO_SOURCE`. Unlike the single-rate POST endpoint, this returns `resourceIds` directly.
|
|
392
392
|
|
|
393
393
|
---
|
|
394
394
|
|
|
@@ -547,7 +547,7 @@ Create defaults: `status=ACTIVE`, `itemCategory=NON_INVENTORY`. Update: only sen
|
|
|
547
547
|
- **`currency: "USD"` (string)** causes "Invalid request body" error (400).
|
|
548
548
|
|
|
549
549
|
**Rate hierarchy** (when using `currency: { sourceCurrency }` without `exchangeRate`):
|
|
550
|
-
1. Org-level rate (set via `/organization
|
|
550
|
+
1. Org-level rate (set via `/organization/currencies/:code/rates`) — auto-filled if exists
|
|
551
551
|
2. Platform rate (ECB via FRANKFURTER) — auto-fetched if no org rate
|
|
552
552
|
3. Transaction-level rate (via `exchangeRate` in the `currency` object) — overrides all
|
|
553
553
|
|
|
@@ -2078,7 +2078,7 @@ Update an existing payment record. All fields optional — only included fields
|
|
|
2078
2078
|
"valueDate": "2026-03-02",
|
|
2079
2079
|
"paymentMethod": "BANK_TRANSFER",
|
|
2080
2080
|
"accountResourceId": "uuid-bank",
|
|
2081
|
-
"currency": { "sourceCurrency": "USD", "exchangeRate":
|
|
2081
|
+
"currency": { "sourceCurrency": "USD", "exchangeRate": 0.74 },
|
|
2082
2082
|
"transactionFee": 5.00,
|
|
2083
2083
|
"transactionFeeCollected": true
|
|
2084
2084
|
}
|
|
@@ -175,21 +175,23 @@ Valid `type` values: `"TEXT"`, `"DATE"`, `"DROPDOWN"` (UPPERCASE).
|
|
|
175
175
|
|
|
176
176
|
## Currency Errors
|
|
177
177
|
|
|
178
|
-
### 404 on rate endpoints —
|
|
179
|
-
**Cause**:
|
|
178
|
+
### 404 on rate endpoints — MALFORMED PATH (common mistake)
|
|
179
|
+
**Cause**: Omitting the currency code, or using singular `rate` instead of `rates`.
|
|
180
180
|
**Endpoints that 404 (wrong paths)**:
|
|
181
|
-
- `/api/v1/organization/currencies/rates` → 404
|
|
182
|
-
- `/api/v1/organization/currencies/USD/rate` → 404
|
|
183
|
-
- `/api/v1/organization/currencies/{id}/rate` → 404
|
|
184
|
-
**Fix**: Rate endpoints
|
|
181
|
+
- `/api/v1/organization/currencies/rates` → 404 (no currency code)
|
|
182
|
+
- `/api/v1/organization/currencies/USD/rate` → 404 (singular)
|
|
183
|
+
- `/api/v1/organization/currencies/{id}/rate` → 404 (singular)
|
|
184
|
+
**Fix**: Rate endpoints live under the nested `/organization/currencies` family. The older
|
|
185
|
+
hyphenated `/organization-currencies/...` rate paths still resolve but are marked
|
|
186
|
+
**deprecated** in the OpenAPI spec — prefer the nested form:
|
|
185
187
|
```
|
|
186
|
-
POST /api/v1/organization
|
|
187
|
-
GET /api/v1/organization
|
|
188
|
-
GET /api/v1/organization
|
|
189
|
-
PUT /api/v1/organization
|
|
190
|
-
DELETE /api/v1/organization
|
|
188
|
+
POST /api/v1/organization/currencies/:currencyCode/rates Set rate
|
|
189
|
+
GET /api/v1/organization/currencies/:currencyCode/rates List rates
|
|
190
|
+
GET /api/v1/organization/currencies/:currencyCode/rates/:id Get rate
|
|
191
|
+
PUT /api/v1/organization/currencies/:currencyCode/rates/:id Update rate
|
|
192
|
+
DELETE /api/v1/organization/currencies/:currencyCode/rates/:id Delete rate
|
|
191
193
|
```
|
|
192
|
-
Enable currencies first via `POST /organization/currencies`, then set rates via `/organization
|
|
194
|
+
Enable currencies first via `POST /organization/currencies`, then set rates via `/organization/currencies/:code/rates`.
|
|
193
195
|
|
|
194
196
|
### "Cannot set rate for organization base currency" (400)
|
|
195
197
|
**Cause**: Trying to POST/PUT a rate for the org's base currency (e.g., SGD for a Singapore org).
|
|
@@ -208,7 +210,7 @@ Enable currencies first via `POST /organization/currencies`, then set rates via
|
|
|
208
210
|
**Fix**: Ensure `rateApplicableTo` is after `rateApplicableFrom`, or omit `rateApplicableTo` entirely.
|
|
209
211
|
|
|
210
212
|
### Rates appear inverted (wrong direction)
|
|
211
|
-
**Cause**: POSTing a sourceToFunctional rate (1 foreign = X base) as the `rate` field, which expects functionalToSource (1 base = X foreign).
|
|
213
|
+
**Cause**: POSTing a sourceToFunctional rate (1 foreign = X base) as the `rate` field, which expects functionalToSource (1 base = X foreign). You do not have to do this by hand: pass your figure as-is with `rateDirection` (`FUNCTIONAL_TO_SOURCE` | `SOURCE_TO_FUNCTIONAL`) and the client inverts and strips it. See SKILL.md Rule 49.
|
|
212
214
|
**Symptom**: UI shows "1 SGD = 0.0088 JPY" instead of "1 SGD ≈ 111 JPY" — the reciprocal of what you intended.
|
|
213
215
|
**Fix**: Invert before POSTing: `rate = 1 / yourRate`. If your data says "1 JPY = 0.009 SGD", POST `rate: 111.11`.
|
|
214
216
|
|
|
@@ -241,11 +243,11 @@ Enable currencies first via `POST /organization/currencies`, then set rates via
|
|
|
241
243
|
**Rate sources in response** (inspect `currencyExchange.rateSource`):
|
|
242
244
|
- `rateSource: "EXTERNAL"`, `providerName: "FRANKFURTER"` — auto-fetched from ECB
|
|
243
245
|
- `rateSource: "INTERNAL_TRANSACTION"`, `providerName: "CUSTOM"` — user-specified `exchangeRate`
|
|
244
|
-
- `rateSource: "INTERNAL_ORG"` — org-level rate (set via `/organization
|
|
246
|
+
- `rateSource: "INTERNAL_ORG"` — org-level rate (set via `/organization/currencies/:code/rates`)
|
|
245
247
|
|
|
246
248
|
### "Invalid request body" (400) — `currency` as string
|
|
247
249
|
**Cause**: Using `currency: "USD"` (string) instead of object form.
|
|
248
|
-
**Fix**: Use object form `currency: { sourceCurrency: "USD" }` or `currency: { sourceCurrency: "USD", exchangeRate:
|
|
250
|
+
**Fix**: Use object form `currency: { sourceCurrency: "USD" }` or `currency: { sourceCurrency: "USD", exchangeRate: 0.74 }`.
|
|
249
251
|
|
|
250
252
|
---
|
|
251
253
|
|
|
@@ -617,7 +619,7 @@ if (acct.code) ctx.coaIds[acct.code] = acct.resourceId;
|
|
|
617
619
|
## Journal Errors
|
|
618
620
|
|
|
619
621
|
### Multi-currency journals — `currency` object
|
|
620
|
-
Journals support a top-level `currency` object to create entries in a foreign currency — **same format as invoices/bills**: `{ "sourceCurrency": "USD" }` (auto-fetch platform rate) or `{ "sourceCurrency": "USD", "exchangeRate":
|
|
622
|
+
Journals support a top-level `currency` object to create entries in a foreign currency — **same format as invoices/bills**: `{ "sourceCurrency": "USD" }` (auto-fetch platform rate) or `{ "sourceCurrency": "USD", "exchangeRate": 0.74 }` (custom rate). The currency must be enabled for the org. Omit the field for base currency journals.
|
|
621
623
|
|
|
622
624
|
```json
|
|
623
625
|
// Base currency journal (omit currency):
|
|
@@ -627,7 +629,7 @@ Journals support a top-level `currency` object to create entries in a foreign cu
|
|
|
627
629
|
{ "saveAsDraft": false, "reference": "JV-001", "valueDate": "2026-02-08", "currency": { "sourceCurrency": "USD" }, "journalEntries": [...] }
|
|
628
630
|
|
|
629
631
|
// Foreign currency journal (custom rate):
|
|
630
|
-
{ "saveAsDraft": false, "reference": "JV-001", "valueDate": "2026-02-08", "currency": { "sourceCurrency": "USD", "exchangeRate":
|
|
632
|
+
{ "saveAsDraft": false, "reference": "JV-001", "valueDate": "2026-02-08", "currency": { "sourceCurrency": "USD", "exchangeRate": 0.74 }, "journalEntries": [...] }
|
|
631
633
|
```
|
|
632
634
|
|
|
633
635
|
**Three restrictions apply to foreign currency journals:**
|
|
@@ -229,7 +229,7 @@ Fixed assets lock their linked line items — cannot edit account, amounts, or e
|
|
|
229
229
|
|
|
230
230
|
**User Roles**: Admin (full access), Preparer (create drafts, submit for approval), Member (own drafts only). Granular permissions by module (AR, AP, Treasury, Journals).
|
|
231
231
|
|
|
232
|
-
**API**: CRUD `GET/POST/PUT/DELETE /chart-of-accounts`, `POST /chart-of-accounts/bulk-upsert`, `POST /chart-of-accounts/search`, `GET /tax-profiles`, `POST /tax-profiles/search`, CRUD `GET/POST/PUT/DELETE /tags`, `POST /tags/search`, CRUD `GET/POST/PUT/DELETE /custom-fields`, `POST /custom-fields/search`, `POST /organization/currencies` (enable), `DELETE /organization/currencies/:code` (disable), `POST /organization
|
|
232
|
+
**API**: CRUD `GET/POST/PUT/DELETE /chart-of-accounts`, `POST /chart-of-accounts/bulk-upsert`, `POST /chart-of-accounts/search`, `GET /tax-profiles`, `POST /tax-profiles/search`, CRUD `GET/POST/PUT/DELETE /tags`, `POST /tags/search`, CRUD `GET/POST/PUT/DELETE /custom-fields`, `POST /custom-fields/search`, `POST /organization/currencies` (enable), `DELETE /organization/currencies/:code` (disable), `POST /organization/currencies/:code/rates` (set FX rate, CRUD), `GET /organization` (org details), CRUD `GET/POST/PUT/DELETE /organization/bookmarks`, CRUD `GET/POST/PUT/DELETE /nano-classifiers`, `POST /nano-classifiers/search`, `GET /organization-users`, `POST /organization-users/search`. Reference data: `GET /account-classifications`, `GET /withholding-tax-codes`, `GET /tax-types`, `GET /modules`
|
|
233
233
|
|
|
234
234
|
---
|
|
235
235
|
|
|
@@ -213,7 +213,7 @@ When POSTing, `classificationType` must be one of these exact strings (same as `
|
|
|
213
213
|
| `lines` | `journalEntries` | Same |
|
|
214
214
|
| `entries` | `journalEntries` | Same |
|
|
215
215
|
| `debit` / `credit` (entry) | `amount` + `type` | `amount`: number, `type`: `"DEBIT"` or `"CREDIT"` (UPPERCASE) |
|
|
216
|
-
| `currency: "USD"` (string) | `currency: { sourceCurrency: "USD" }` | **Object form** — same as invoices/bills. Auto-fetches platform rate. Add `exchangeRate:
|
|
216
|
+
| `currency: "USD"` (string) | `currency: { sourceCurrency: "USD" }` | **Object form** — same as invoices/bills. Auto-fetches platform rate. Add `exchangeRate: 0.74` for custom rate. Omit for base currency. |
|
|
217
217
|
|
|
218
218
|
### Bulk upsert (`POST /journals/bulk-upsert`)
|
|
219
219
|
|
|
@@ -460,7 +460,7 @@ DELETE → expects "A" (parentEntityResourceId, via /cash-entries/:id)
|
|
|
460
460
|
|
|
461
461
|
| What You'd Guess | Actual API Field | Notes |
|
|
462
462
|
|------------------|-------------------|-------|
|
|
463
|
-
| `/organization
|
|
463
|
+
| `/organization-currencies/:code/rates` (older docs) | `/organization/currencies/:code/rates` | Nested path is current; hyphenated form is **deprecated** in the spec |
|
|
464
464
|
| `exchangeRate` (rate POST body) | `rate` | Just `rate`, not `exchangeRate` |
|
|
465
465
|
| `effectiveDate` / `valueDate` / `date` | `rateApplicableFrom` | Rate start date, `YYYY-MM-DD` only |
|
|
466
466
|
| `expiryDate` | `rateApplicableTo` | Optional rate end date |
|
|
@@ -470,9 +470,9 @@ DELETE → expects "A" (parentEntityResourceId, via /cash-entries/:id)
|
|
|
470
470
|
| `baseCurrency` (GET response) | `functionalCurrencyCode` | The org's base currency code in rate response |
|
|
471
471
|
| `notes` (GET response) | `notes: { date, name }` | Metadata object — `date` is the creation date, `name` is the creator |
|
|
472
472
|
|
|
473
|
-
> **Rate direction cheat-sheet**: POST `rate` = GET `rateFunctionalToSource` = "1 base → X foreign". If your data is "1 foreign → X base", **invert before POSTing
|
|
473
|
+
> **Rate direction cheat-sheet**: POST `rate` = GET `rateFunctionalToSource` = "1 base → X foreign". If your data is "1 foreign → X base", **invert before POSTing** — or set `rateDirection: "SOURCE_TO_FUNCTIONAL"` and let the client do it (Rule 49).
|
|
474
474
|
|
|
475
|
-
**Rate POST response gotcha**: `POST /organization
|
|
475
|
+
**Rate POST response gotcha**: `POST /organization/currencies/:code/rates` returns `{ "data": "Rate added successfully" }` — a **plain string**, NOT a CurrencyRate object. No `resourceId` is returned. To get the rate's `resourceId` for later PUT/DELETE, follow up with GET and match by `rateApplicableFrom`.
|
|
476
476
|
|
|
477
477
|
---
|
|
478
478
|
|
|
@@ -582,8 +582,8 @@ DELETE → expects "A" (parentEntityResourceId, via /cash-entries/:id)
|
|
|
582
582
|
| `GET /organization/currencies` | `{ data: { data: [...] } }` | `{ data: [...] }` |
|
|
583
583
|
| `POST /chart-of-accounts/bulk-upsert` | `{ data: { resourceIds: [...] } }` | Individual results |
|
|
584
584
|
| `POST /organization/currencies` | `{ data: { resourceIds: [...] } }` | Confirmation object |
|
|
585
|
-
| `POST /organization
|
|
586
|
-
| `PUT /organization
|
|
585
|
+
| `POST /organization/currencies/:code/rates` | `{ data: "Rate added successfully" }` (string!) | `{ data: { resourceId } }` (object) |
|
|
586
|
+
| `PUT /organization/currencies/:code/rates/:id` | `{ data: "Rate updated successfully" }` (string!) | `{ data: { resourceId } }` (object) |
|
|
587
587
|
| `GET /invoices/{id}` line items | `organizationAccountResourceId` | `accountResourceId` (POST uses `accountResourceId`) |
|
|
588
588
|
| `POST /invoices` (create) | `{ resourceId }` only | Full entity (minimal response!) |
|
|
589
589
|
| `POST /bills` (create) | `{ resourceId }` only | Full entity (minimal response!) |
|
|
@@ -606,7 +606,7 @@ Battle-tested patterns from production Jaz API clients:
|
|
|
606
606
|
| Bill payments | Always embedded in bill creation body, never standalone |
|
|
607
607
|
| Bank records | JSON POST `/bank-records/:id` or multipart `/magic/importBankStatementFromAttachment`. Search via `/bank-records/:id/search`. |
|
|
608
608
|
| Scheduled bills | Wrapped as `{ repeat, startDate, endDate, bill: {...} }`. Field is `repeat` (NOT `frequency`/`interval`) |
|
|
609
|
-
| FX currency | MUST use `currency` OBJECT on ALL transaction types (invoices, bills, credit notes, journals): `{ sourceCurrency: "USD" }` (auto platform rate) or `{ sourceCurrency: "USD", exchangeRate:
|
|
609
|
+
| FX currency | MUST use `currency` OBJECT on ALL transaction types (invoices, bills, credit notes, journals): `{ sourceCurrency: "USD" }` (auto platform rate) or `{ sourceCurrency: "USD", exchangeRate: 0.74 }` (custom). String `currencyCode` silently ignored. `exchangeRate` = functionalToSource; invert an everyday "1 USD = 1.35 SGD" quote (Rule 49). |
|
|
610
610
|
|
|
611
611
|
---
|
|
612
612
|
|
|
@@ -307,17 +307,17 @@ Body for all three: `{ items: [{btResourceId: "<uuid>", btType: "SALE|PURCHASE|S
|
|
|
307
307
|
| GET | `/organization/currencies/:currencyCode` | Get by code |
|
|
308
308
|
| DELETE | `/organization/currencies/:currencyCode` | Disable currency |
|
|
309
309
|
|
|
310
|
-
### Currency Rates (via /organization
|
|
310
|
+
### Currency Rates (via /organization/currencies)
|
|
311
311
|
| Method | Path | Description |
|
|
312
312
|
|--------|------|-------------|
|
|
313
|
-
| POST | `/organization
|
|
314
|
-
| GET | `/organization
|
|
315
|
-
| GET | `/organization
|
|
316
|
-
| PUT | `/organization
|
|
317
|
-
| DELETE | `/organization
|
|
313
|
+
| POST | `/organization/currencies/:currencyCode/rates` | Set custom rate |
|
|
314
|
+
| GET | `/organization/currencies/:currencyCode/rates` | List rates |
|
|
315
|
+
| GET | `/organization/currencies/:currencyCode/rates/:resourceId` | Get rate |
|
|
316
|
+
| PUT | `/organization/currencies/:currencyCode/rates/:resourceId` | Update rate |
|
|
317
|
+
| DELETE | `/organization/currencies/:currencyCode/rates/:resourceId` | Delete rate |
|
|
318
318
|
| POST | `/organization/currencies/rates/bulk-upsert` | Bulk create exchange rates (max 500, auto-enables currencies) |
|
|
319
319
|
|
|
320
|
-
**
|
|
320
|
+
**Path note**: rate management, enable/disable and bulk-upsert all live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths still resolve but are marked **deprecated** in the OpenAPI spec — prefer the nested form. POST body: `{ "rate": 0.74, "rateApplicableFrom": "YYYY-MM-DD" }` (rate = 1 base → X foreign; see endpoints.md for direction details). Base currency rates return 400. See endpoints.md for full examples.
|
|
321
321
|
|
|
322
322
|
---
|
|
323
323
|
|
|
@@ -183,9 +183,8 @@ Same subcommands and flags as `cash-in`.
|
|
|
183
183
|
|------------|-----------|
|
|
184
184
|
| `list <code>` | `--limit`, `--offset`, `--all`, `--format`, `--json` |
|
|
185
185
|
| `add <code>` | `--rate`, `--from`, `--to` |
|
|
186
|
-
| `update <rateId>` | `--rate`, `--from`, `--to` |
|
|
187
|
-
| `
|
|
188
|
-
| `import-status <jobId>` | Check import job status |
|
|
186
|
+
| `update <code> <rateId>` | `--rate`, `--from`, `--to` |
|
|
187
|
+
| `bulk-upsert` | `--input <file>` (max 500 rates; requires `rateDirection` per rate) |
|
|
189
188
|
|
|
190
189
|
### `clio tax-profiles` — Tax profiles and tax types
|
|
191
190
|
| Subcommand | Key flags |
|
|
@@ -472,7 +471,7 @@ All calculators work offline (no auth). Use `--json` for structured output.
|
|
|
472
471
|
| `depreciation` | `--cost`, `--salvage`, `--life`, `--method` |
|
|
473
472
|
| `prepaid-expense` | `--amount`, `--start-date`, `--months` |
|
|
474
473
|
| `deferred-revenue` | `--amount`, `--start-date`, `--months` |
|
|
475
|
-
| `fx-reval` | `--amount`, `--
|
|
474
|
+
| `fx-reval` | `--amount`, `--book-rate`, `--closing-rate`, `--rate-direction`, `--currency` |
|
|
476
475
|
| `ecl` | `--receivables`, `--aging-buckets` (via `--input`) |
|
|
477
476
|
| `provision` | `--amount`, `--rate`, `--periods` |
|
|
478
477
|
| `fixed-deposit` | `--principal`, `--rate`, `--term` |
|
|
@@ -98,8 +98,10 @@ Handle a foreign currency invoice from start to finish.
|
|
|
98
98
|
# Add USD currency to the org (idempotent — safe to re-run)
|
|
99
99
|
clio currencies add USD
|
|
100
100
|
|
|
101
|
-
# Set the exchange rate for the period
|
|
102
|
-
|
|
101
|
+
# Set the exchange rate for the period.
|
|
102
|
+
# --rate is functionalToSource: 1 SGD = 0.7435 USD. Invert an everyday
|
|
103
|
+
# "1 USD = 1.3450 SGD" quote before sending (1 / 1.3450 = 0.7435).
|
|
104
|
+
clio currency-rates add USD --rate 0.7435 --from 2026-03-01 --to 2026-03-31
|
|
103
105
|
|
|
104
106
|
# For bulk updates, prepare a JSON file and use bulk-upsert (max 500 rates/call)
|
|
105
107
|
clio currency-rates bulk-upsert --input rates.json
|
|
@@ -111,7 +113,7 @@ clio invoices create \
|
|
|
111
113
|
--due 2026-04-15 \
|
|
112
114
|
--ref "INV-USD-001" \
|
|
113
115
|
--currency USD \
|
|
114
|
-
--rate
|
|
116
|
+
--exchange-rate 0.7435 \
|
|
115
117
|
--lines '[{"name":"Software License","quantity":1,"unitPrice":2000,"accountResourceId":"Revenue"}]' \
|
|
116
118
|
--finalize
|
|
117
119
|
|
|
@@ -9,11 +9,11 @@ Enable currencies and set FYE closing rates before creating any FX transactions:
|
|
|
9
9
|
POST /api/v1/organization/currencies // Enable currency
|
|
10
10
|
{ "currencies": ["USD"] }
|
|
11
11
|
|
|
12
|
-
POST /api/v1/organization
|
|
13
|
-
{ "rate":
|
|
12
|
+
POST /api/v1/organization/currencies/USD/rates // Set FYE rate
|
|
13
|
+
{ "rate": 0.74, "rateApplicableFrom": "2024-12-31" }
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
**Rate direction:** Jaz uses `functionalToSource` — how many
|
|
16
|
+
**Rate direction:** Jaz uses `functionalToSource` — how many SOURCE (foreign) units per 1 FUNCTIONAL (base) unit. If base = SGD and the quote is "1 USD = 1.35 SGD", that quote is the inverse: `rate = 1 / 1.35 = 0.74`. Invert only when the quote is written foreign-first; a USD-base org quoting "1 USD = 56.5 PHP" already has the right direction and sends `56.5`. Rather than deciding, set `rateDirection` and pass the figure verbatim (SKILL.md Rule 49).
|
|
17
17
|
|
|
18
18
|
**CRITICAL:** `currencyCode: "USD"` (string) is **silently ignored** by the API — it creates the transaction in base currency. You MUST use the `currency` object form.
|
|
19
19
|
|
|
@@ -27,7 +27,7 @@ FX conversion transactions use **original dates** (for aging) but an **explicit
|
|
|
27
27
|
"dueDate": "2024-07-15",
|
|
28
28
|
"currency": {
|
|
29
29
|
"sourceCurrency": "USD",
|
|
30
|
-
"exchangeRate":
|
|
30
|
+
"exchangeRate": 0.74
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
```
|
|
@@ -222,16 +222,16 @@ POST /api/v1/organization/currencies
|
|
|
222
222
|
For Quick Conversion, all conversion transactions use the FYE closing rate. Rates MUST be set AFTER currencies are enabled:
|
|
223
223
|
|
|
224
224
|
```
|
|
225
|
-
POST /api/v1/organization
|
|
225
|
+
POST /api/v1/organization/currencies/<code>/rates
|
|
226
226
|
{
|
|
227
|
-
"rate":
|
|
227
|
+
"rate": 0.74,
|
|
228
228
|
"rateApplicableFrom": "2023-12-31"
|
|
229
229
|
}
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
-
**Rate direction:** `functionalToSource` — how many units of
|
|
232
|
+
**Rate direction:** `functionalToSource` — how many units of SOURCE (foreign) currency = 1 unit of FUNCTIONAL (base) currency. Example: base SGD, 1 SGD = 0.74 USD → rate = 0.74. A quote written foreign-first ("1 USD = 1.35 SGD") is the inverse — send 1/1.35 = 0.74, or send 1.35 with `rateDirection: "SOURCE_TO_FUNCTIONAL"` and let the client invert.
|
|
233
233
|
|
|
234
|
-
**Note:** Rate endpoints
|
|
234
|
+
**Note:** Rate endpoints and enable/disable both live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths are **deprecated** in the OpenAPI spec.
|
|
235
235
|
|
|
236
236
|
**CRITICAL:** The field is `rateApplicableFrom` (NOT `effectiveDate`). Using the wrong field name will silently fail.
|
|
237
237
|
|
|
@@ -93,7 +93,7 @@ POST /api/v1/invoices
|
|
|
93
93
|
|
|
94
94
|
**Dates:** Use original dates from the aging report (preserves aging schedules). Fall back to FYE date if not available.
|
|
95
95
|
|
|
96
|
-
**FX invoices:** Use `currency: { sourceCurrency: "USD", exchangeRate:
|
|
96
|
+
**FX invoices:** Use `currency: { sourceCurrency: "USD", exchangeRate: 0.74 }` (object form with explicit FYE rate). The `exchangeRate` field overrides Jaz's auto-fetch, ensuring zero UGL on day 1. See "FX Invoices/Bills — Dates vs. Rates" in Edge Cases below.
|
|
97
97
|
|
|
98
98
|
#### 2.2 Conversion Bills (AP)
|
|
99
99
|
For each line in the AP Aging report:
|
|
@@ -193,7 +193,7 @@ POST /api/v1/invoices
|
|
|
193
193
|
"dueDate": "<original due date>", // preserves aging buckets
|
|
194
194
|
"currency": {
|
|
195
195
|
"sourceCurrency": "USD",
|
|
196
|
-
"exchangeRate":
|
|
196
|
+
"exchangeRate": 0.74 // explicit FYE rate — overrides auto-fetch
|
|
197
197
|
},
|
|
198
198
|
...
|
|
199
199
|
}
|
|
@@ -207,7 +207,7 @@ POST /api/v1/invoices
|
|
|
207
207
|
|
|
208
208
|
**When dates aren't available:** Some aging reports only show contact name + amount (no individual dates). In this case, fall back to FYE date for both valueDate and dueDate. Aging schedules will be flat ("current") but FX handling remains correct.
|
|
209
209
|
|
|
210
|
-
**Rate source:** FYE rates come from the exchange rates file (e.g., MAS closing rates). They're set on the org in Phase 1 via `POST /organization
|
|
210
|
+
**Rate source:** FYE rates come from the exchange rates file (e.g., MAS closing rates). They're set on the org in Phase 1 via `POST /organization/currencies/:code/rates` and also passed explicitly on each FX transaction to guarantee the rate is used regardless of valueDate.
|
|
211
211
|
|
|
212
212
|
### Partially Paid Invoices in AR Aging
|
|
213
213
|
The AR Aging shows only the **outstanding** balance. Create the conversion invoice for the outstanding amount only — the historical payments are not relevant for Quick Conversion.
|
|
@@ -108,11 +108,11 @@ Conversion Bills (AP) XX
|
|
|
108
108
|
TTB Journal 1
|
|
109
109
|
Lock Date Set <FYE date>
|
|
110
110
|
|
|
111
|
-
FX RATES APPLIED
|
|
111
|
+
FX RATES APPLIED (functionalToSource — 1 base unit = N foreign)
|
|
112
112
|
--------------------------------------------
|
|
113
|
-
USD
|
|
114
|
-
EUR
|
|
115
|
-
JPY
|
|
113
|
+
USD 0.7407
|
|
114
|
+
EUR 0.6897
|
|
115
|
+
JPY 108.6957
|
|
116
116
|
|
|
117
117
|
ERRORS (if any)
|
|
118
118
|
--------------------------------------------
|
|
@@ -164,7 +164,9 @@ generate_general_ledger(period_end: '2025-01-31', accountResourceIds: [<FX accou
|
|
|
164
164
|
|
|
165
165
|
2. For each foreign-currency monetary balance at period end (from a separate `generate_general_ledger` filtered to non-base-currency accounts), independently compute:
|
|
166
166
|
```
|
|
167
|
-
|
|
167
|
+
# --rate-direction is REQUIRED. A list_currency_rates value is FUNCTIONAL_TO_SOURCE
|
|
168
|
+
# and can be passed as-is; an everyday "1 USD = 1.35 SGD" quote is SOURCE_TO_FUNCTIONAL.
|
|
169
|
+
clio calc fx-reval --amount <foreign> --book-rate <historical> --closing-rate <rateFunctionalToSource at 2025-01-31> --rate-direction FUNCTIONAL_TO_SOURCE --currency <code> --base-currency <base currency> --json
|
|
168
170
|
```
|
|
169
171
|
|
|
170
172
|
3. Sum your independent gain/loss across all foreign balances. Compare against Jaz's auto-posted FX totals from step 1. Variance > materiality threshold → investigate (see the `fx-reval` recipe for likely causes — settlement-realized FX shifts, explicit `currency.exchangeRate` overrides, multi-leg FX through bank-side spreads).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-recipes
|
|
3
|
-
version: 5.
|
|
3
|
+
version: 5.35.0
|
|
4
4
|
description: >-
|
|
5
5
|
Use this skill when modeling complex multi-step accounting transactions —
|
|
6
6
|
anything that spans multiple periods, involves changing amounts, or requires
|
|
@@ -189,7 +189,9 @@ clio calc asset-disposal --cost 50000 --salvage 5000 --life 5 --acquired 2022-01
|
|
|
189
189
|
|
|
190
190
|
# FX revaluation — unrealized gain/loss on non-AR/AP items (IAS 21)
|
|
191
191
|
# Typical context: month-end close (period-end FX reval) + year-end (revaluation)
|
|
192
|
-
|
|
192
|
+
# --rate-direction is REQUIRED — these rates read foreign-first (1 USD = 1.35 SGD).
|
|
193
|
+
# A list_currency_rates value would be FUNCTIONAL_TO_SOURCE instead.
|
|
194
|
+
clio calc fx-reval --amount 50000 --book-rate 1.35 --closing-rate 1.38 --rate-direction SOURCE_TO_FUNCTIONAL [--position ASSET|LIABILITY] [--currency USD] [--base-currency SGD] [--json]
|
|
193
195
|
|
|
194
196
|
# Expected credit loss provision matrix (IFRS 9)
|
|
195
197
|
# Typical context: GST/VAT filing cycle (ECL reviewed alongside the return prep) + year-end (ECL true-up)
|