@countfinancial/cli 0.2.1 → 0.2.3
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/LICENSE +15 -0
- package/dist/__tests__/credentialStore.test.js +9 -0
- package/dist/__tests__/credentialStore.test.js.map +1 -1
- package/dist/cli.js +14 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/testTools.command.d.ts +7 -0
- package/dist/commands/testTools.command.js +42 -0
- package/dist/commands/testTools.command.js.map +1 -0
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/helpers/toolSmokeTestFixtures.helper.d.ts +16 -0
- package/dist/helpers/toolSmokeTestFixtures.helper.js +491 -0
- package/dist/helpers/toolSmokeTestFixtures.helper.js.map +1 -0
- package/dist/partner-mcp/helpers/mcpKnowledge.helper.js +114 -4
- package/dist/partner-mcp/helpers/mcpKnowledge.helper.js.map +1 -1
- package/dist/partner-mcp/helpers/mcpPayloadValidation.helper.d.ts +1 -1
- package/dist/partner-mcp/helpers/mcpPayloadValidation.helper.js +61 -84
- package/dist/partner-mcp/helpers/mcpPayloadValidation.helper.js.map +1 -1
- package/dist/partner-mcp/helpers/mcpPlaybooks.helper.js +181 -2
- package/dist/partner-mcp/helpers/mcpPlaybooks.helper.js.map +1 -1
- package/dist/partner-mcp/helpers/mcpRecoveryHint.helper.js +79 -0
- package/dist/partner-mcp/helpers/mcpRecoveryHint.helper.js.map +1 -1
- package/dist/partner-mcp/schemas/bodies.d.ts +584 -0
- package/dist/partner-mcp/schemas/bodies.js +440 -0
- package/dist/partner-mcp/schemas/bodies.js.map +1 -0
- package/dist/partner-mcp/schemas/builders.d.ts +36 -0
- package/dist/partner-mcp/schemas/builders.js +106 -0
- package/dist/partner-mcp/schemas/builders.js.map +1 -0
- package/dist/partner-mcp/schemas/index.d.ts +5 -0
- package/dist/partner-mcp/schemas/index.js +6 -0
- package/dist/partner-mcp/schemas/index.js.map +1 -0
- package/dist/partner-mcp/schemas/primitives.d.ts +39 -0
- package/dist/partner-mcp/schemas/primitives.js +107 -0
- package/dist/partner-mcp/schemas/primitives.js.map +1 -0
- package/dist/partner-mcp/schemas/queries.d.ts +311 -0
- package/dist/partner-mcp/schemas/queries.js +175 -0
- package/dist/partner-mcp/schemas/queries.js.map +1 -0
- package/dist/partner-mcp/schemas/toolInputSchemas.d.ts +23 -0
- package/dist/partner-mcp/schemas/toolInputSchemas.js +263 -0
- package/dist/partner-mcp/schemas/toolInputSchemas.js.map +1 -0
- package/dist/partner-mcp/tools/definitions.js +106 -135
- package/dist/partner-mcp/tools/definitions.js.map +1 -1
- package/dist/partner-mcp/tools/registerTools.d.ts +8 -0
- package/dist/partner-mcp/tools/registerTools.js +8 -3
- package/dist/partner-mcp/tools/registerTools.js.map +1 -1
- package/dist/services/toolSmokeTest.service.d.ts +38 -0
- package/dist/services/toolSmokeTest.service.js +495 -0
- package/dist/services/toolSmokeTest.service.js.map +1 -0
- package/package.json +4 -3
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
const
|
|
1
|
+
import * as toolInputSchemas from '../schemas/toolInputSchemas.js';
|
|
2
|
+
const rawTools = [
|
|
3
3
|
{
|
|
4
4
|
name: 'COUNT_auth_status',
|
|
5
5
|
title: 'COUNT Auth Status',
|
|
6
6
|
description: 'Return the MCP server authentication configuration state without exposing secrets.',
|
|
7
7
|
method: 'GET',
|
|
8
8
|
pathTemplate: '/__local/auth-status',
|
|
9
|
-
inputSchema: emptyInputSchema,
|
|
10
9
|
requiresUserAuth: false,
|
|
11
10
|
readOnly: true,
|
|
12
11
|
destructive: false,
|
|
@@ -17,7 +16,6 @@ const tools = [
|
|
|
17
16
|
description: 'Return human-readable guidance for a specific COUNT tool, including the partner API path it wraps, expected query/body fields from the public COUNT developer documentation, and tips for which IDs to pass. Useful for checking request shape before unfamiliar create/update operations.',
|
|
18
17
|
method: 'GET',
|
|
19
18
|
pathTemplate: '/__local/describe-endpoint',
|
|
20
|
-
inputSchema: describeEndpointInputSchema,
|
|
21
19
|
requiresUserAuth: false,
|
|
22
20
|
readOnly: true,
|
|
23
21
|
destructive: false,
|
|
@@ -28,7 +26,6 @@ const tools = [
|
|
|
28
26
|
description: 'COUNT connector and workflow FAQ — call this for “how do I…?” questions before guessing. Covers: authorizing additional workspaces (disconnect + reconnect), Claude/ChatGPT reconnect steps, multiple workspace usage, why auth_status may show fewer workspaces than the COUNT web app, external UUID conventions, P&L category filters (e.g. shipping/Freight & Courier), and bulk import batch sizes. Optional input: `topic` (FAQ id) or `search` (free text). Omit both to list all topics with summaries.',
|
|
29
27
|
method: 'GET',
|
|
30
28
|
pathTemplate: '/__local/knowledge',
|
|
31
|
-
inputSchema: knowledgeInputSchema,
|
|
32
29
|
requiresUserAuth: false,
|
|
33
30
|
readOnly: true,
|
|
34
31
|
destructive: false,
|
|
@@ -36,10 +33,9 @@ const tools = [
|
|
|
36
33
|
{
|
|
37
34
|
name: 'COUNT_playbooks',
|
|
38
35
|
title: 'COUNT Playbooks',
|
|
39
|
-
description: 'End-to-end accounting workflows with ordered steps and tool names. Call before multi-step tasks such as paying a vendor bill, bulk migration imports, or month-end review. Optional input: `playbook` (id) or `search` (free text). Omit both to list all playbooks with summaries. Playbook ids: pay_vendor_bill, migration_import, month_end_review.',
|
|
36
|
+
description: 'End-to-end accounting workflows with ordered steps and tool names. Call before multi-step tasks such as paying a vendor bill, creating and sending an invoice, bulk migration imports, chart-of-accounts setup with transaction import, budget planning with actuals review, or month-end review. Optional input: `playbook` (id) or `search` (free text). Omit both to list all playbooks with summaries. Playbook ids: pay_vendor_bill, create_invoice_and_send, migration_import, budget_import, month_end_review, setup_accounts_and_import_transactions, plan_budget_and_review_actuals.',
|
|
40
37
|
method: 'GET',
|
|
41
38
|
pathTemplate: '/__local/playbooks',
|
|
42
|
-
inputSchema: playbooksInputSchema,
|
|
43
39
|
requiresUserAuth: false,
|
|
44
40
|
readOnly: true,
|
|
45
41
|
destructive: false,
|
|
@@ -50,7 +46,6 @@ const tools = [
|
|
|
50
46
|
description: 'Resolve human-readable vendor, customer, account, project, or tag names to external COUNT UUIDs for this workspace. Pass one or more name fields; each returns uuid, matchConfidence (exact/fuzzy/ambiguous/not_found), and candidates when ambiguous. Use before bulk imports instead of guessing UUIDs from large list results.',
|
|
51
47
|
method: 'GET',
|
|
52
48
|
pathTemplate: '/__local/resolve-references',
|
|
53
|
-
inputSchema: resolveReferencesInputSchema,
|
|
54
49
|
requiresUserAuth: false,
|
|
55
50
|
readOnly: true,
|
|
56
51
|
destructive: false,
|
|
@@ -58,10 +53,9 @@ const tools = [
|
|
|
58
53
|
{
|
|
59
54
|
name: 'COUNT_validate_payload',
|
|
60
55
|
title: 'Validate Payload',
|
|
61
|
-
description: 'Preflight validation for
|
|
56
|
+
description: 'Preflight validation for partner API tool payloads — no data is written. Runs typed schema validation on query and body, bulk batch size (cap 100), legacy numeric field rejection, and required fields for bulk create and create_bill. Set verifyReferences: true to confirm UUIDs exist in the workspace. Works for list and mutation tools.',
|
|
62
57
|
method: 'GET',
|
|
63
58
|
pathTemplate: '/__local/validate-payload',
|
|
64
|
-
inputSchema: validatePayloadInputSchema,
|
|
65
59
|
requiresUserAuth: false,
|
|
66
60
|
readOnly: true,
|
|
67
61
|
destructive: false,
|
|
@@ -72,7 +66,6 @@ const tools = [
|
|
|
72
66
|
description: 'Refresh the COUNT partner access token using the configured refresh token. The refreshed token is kept in this MCP process memory.',
|
|
73
67
|
method: 'POST',
|
|
74
68
|
pathTemplate: '/partners/refresh-user-access-token',
|
|
75
|
-
inputSchema: emptyInputSchema,
|
|
76
69
|
requiresUserAuth: false,
|
|
77
70
|
readOnly: false,
|
|
78
71
|
destructive: false,
|
|
@@ -81,10 +74,9 @@ const tools = [
|
|
|
81
74
|
{
|
|
82
75
|
name: 'COUNT_list_transactions',
|
|
83
76
|
title: 'List Transactions',
|
|
84
|
-
description: 'List register/bank transactions for the authenticated workspace.
|
|
77
|
+
description: 'List register/bank transactions for the authenticated workspace. Returns transaction rows with `id` as the external UUID — pass that UUID to update/change-category/delete tools. Filter fields are documented on the `query` input schema.',
|
|
85
78
|
method: 'GET',
|
|
86
79
|
pathTemplate: '/partners/transactions',
|
|
87
|
-
inputSchema: queryInputSchema,
|
|
88
80
|
requiresUserAuth: true,
|
|
89
81
|
readOnly: true,
|
|
90
82
|
destructive: false,
|
|
@@ -95,7 +87,6 @@ const tools = [
|
|
|
95
87
|
description: 'Get a single transaction by external UUID. Returns transactions hidden from the workspace UI as well. Optional `query` fields are forwarded as Sequelize `include` directives to expand related entities (e.g. category, vendor, customer, tags, taxes). Use the returned `id` (the external UUID) as the next call argument for `update_transaction`, `change_transaction_category`, or `delete_transaction`.',
|
|
96
88
|
method: 'GET',
|
|
97
89
|
pathTemplate: '/partners/transactions/{id}',
|
|
98
|
-
inputSchema: idInputSchema,
|
|
99
90
|
requiresUserAuth: true,
|
|
100
91
|
readOnly: true,
|
|
101
92
|
destructive: false,
|
|
@@ -106,7 +97,6 @@ const tools = [
|
|
|
106
97
|
description: 'Create a register/bank transaction in the authenticated COUNT workspace. **Set the category, vendor/customer, project, tags, and taxes in this single call — do NOT follow up with `change_transaction_category` when you already know the category at creation time.** The create endpoint resolves the category UUID, posts the journal entries, and writes tax associations atomically. Required body: `accUuid` (account UUID from `list_accounts` — the bank/cash account the money moves through), `amount` (positive decimal — see sign convention below), and either `postedDate` or `date` (YYYY-MM-DD). Optional body: `description`, `currency`, `type` (`Expense` | `Income` | `Transfer` | `Journal Entry` — case-sensitive, but lowercase `expense`/`income`/`transfer`/`journal`/`journal_entry` are also accepted and normalized server-side), `categoryAccountUuid` (income/expense category — same UUID source as `accUuid`; **set this here at creation, no separate `change_transaction_category` call needed**), `vendorUuid`, `customerUuid`, `projectUuid`, `tagUuids: string[]`, `taxes: number[]` (numeric internal tax ids — taxes are not yet UUID-resolved on the partner API), `notes`, `authorizedDate`. **Sign convention**: pass `amount` as a positive number; the server flips the sign for income internally. **Type omission**: when `type` is not sent, the server infers it from the category-account type. **FK resolution**: `vendorUuid`/`customerUuid`/`projectUuid`/`tagUuids` are resolved into the internal numeric ids the service expects; do not send `vendorId`/`customerId`/`projectId`/`tags` numeric arrays unless you really do have internal ids. **Use `change_transaction_category` only to modify the category on an EXISTING transaction.**',
|
|
107
98
|
method: 'POST',
|
|
108
99
|
pathTemplate: '/partners/transactions',
|
|
109
|
-
inputSchema: bodyInputSchema,
|
|
110
100
|
requiresUserAuth: true,
|
|
111
101
|
readOnly: false,
|
|
112
102
|
destructive: false,
|
|
@@ -117,7 +107,6 @@ const tools = [
|
|
|
117
107
|
description: 'Create up to 100 register/bank transactions in a single call. Body: `{ "transactions": [<row>, ...] }` where each `<row>` uses the EXACT same shape as `COUNT_create_transaction` (required `accUuid`, `amount`, `postedDate`/`date`; optional `description`, `currency`, `type`, `categoryAccountUuid`, `vendorUuid`, `customerUuid`, `projectUuid`, `tagUuids: string[]`, `taxes: number[]`, `notes`, `authorizedDate`). **Set the category, vendor/customer, project, tags, and taxes ON EACH ROW in this single call — no follow-up `change_transaction_category` needed.** **Partial-success contract**: each row runs in its own DB transaction; one row failing never rolls back another row\'s writes. Response envelope: `{ "successCount": N, "errorCount": M, "results": [{ "index": 0, "success": true, "transaction": {...} } | { "index": 1, "success": false, "error": "..." }, ...] }` — read `errorCount` first; if non-zero, iterate `results` and only retry the rows where `success: false`. The HTTP status is always `201` when the batch was accepted, even if all rows failed. **Cap**: 100 rows per call (split larger imports into multiple calls). **Recommended batch size**: ~25 rows for large historical imports (e.g. billing-system backfills); larger batches increase timeout risk. **Use cases**: ingest a CSV of bank transactions, replay a missed sync window, backfill historical activity. For a single transaction, prefer `COUNT_create_transaction` — the response shape is simpler.',
|
|
118
108
|
method: 'POST',
|
|
119
109
|
pathTemplate: '/partners/transactions/bulk',
|
|
120
|
-
inputSchema: bodyInputSchema,
|
|
121
110
|
requiresUserAuth: true,
|
|
122
111
|
readOnly: false,
|
|
123
112
|
destructive: false,
|
|
@@ -128,7 +117,6 @@ const tools = [
|
|
|
128
117
|
description: 'Update non-category fields on an EXISTING transaction by external UUID. Body fields: `vendorUuid`, `customerUuid`, `projectUuid`, `tagUuids: string[]` (replaces all tags — `[]` clears them), plus regular safe Transaction columns (`description`, `notes`, `amount`, `postedDate`, `authorizedDate`, etc.). Do not send `categoryAccountUuid` or `categoryAccountId` here; use `COUNT_change_transaction_category` to change/clear the category on an existing transaction so taxes, transfers, fixed assets, and journal side effects run through the accounting workflow. (When CREATING a new transaction, pass `categoryAccountUuid` directly to `COUNT_create_transaction` — no follow-up call is needed.) The response includes `_partnerWarnings: [{ field, reason, message }]` when fields you sent were ignored (`reason: "internal_only"` for fields managed internally — e.g. `linkedTransferTransactionId`, `providerTransactionId`, `billId`; `reason: "unknown_field"` for typos / fields not on the transaction model).',
|
|
129
118
|
method: 'PATCH',
|
|
130
119
|
pathTemplate: '/partners/transactions/{id}',
|
|
131
|
-
inputSchema: idBodyInputSchema,
|
|
132
120
|
requiresUserAuth: true,
|
|
133
121
|
readOnly: false,
|
|
134
122
|
destructive: false,
|
|
@@ -139,7 +127,6 @@ const tools = [
|
|
|
139
127
|
description: 'Change, clear, or transfer-link the category (GL account) on an EXISTING transaction by external UUID. **Use this tool only when modifying the category of a transaction that already exists.** When creating a NEW transaction, pass `categoryAccountUuid` directly to `COUNT_create_transaction` instead — the create endpoint resolves the category, posts the journal entries, and writes tax associations in a single call (no follow-up `change_transaction_category` is needed). Body: `categoryAccountUuid` (the `id`, `accUuid`, or `accountUuid` of the target account from `list_accounts`); pass `null` to uncategorize. Optional body fields: `notes`, `taxes`, `autoCreateMatching`, `autoReview`, `linkedTransferTransactionUuid` (or UUID-shaped `linkedTransferTransactionId` from `list_transactions`), `fixedAssetAssignment`. The category-change workflow ensures taxes, transfers, fixed assets, and journal side effects all stay in sync on existing rows.',
|
|
140
128
|
method: 'PATCH',
|
|
141
129
|
pathTemplate: '/partners/transactions/{id}/change-category',
|
|
142
|
-
inputSchema: idBodyInputSchema,
|
|
143
130
|
requiresUserAuth: true,
|
|
144
131
|
readOnly: false,
|
|
145
132
|
destructive: false,
|
|
@@ -150,7 +137,16 @@ const tools = [
|
|
|
150
137
|
description: 'Apply an existing bank/expense/income transaction as payment against one or more invoices or bills. URL `{id}` is the transaction UUID from `list_transactions`. Body: `{ matchingType: "invoice" | "bill", records: [{ id: <invoice or bill UUID>, paymentAmount: <decimal>, notes?: string }], withCaution?: boolean, parentCategoryAccountUuid?: string }`. For invoices use `matchingType: "invoice"` with an **Income** transaction (bank deposit); invoice refunds use **Expense**. For bills use `matchingType: "bill"` with an **Expense** transaction (vendor payment); vendor memos use **Income**. `paymentAmount` must not exceed the document open balance; partial payments may split the transaction. Optional `parentCategoryAccountUuid` sets the category for any remainder when the payment is less than the transaction amount. Do not set `invoiceId` / `billId` on transaction update — use this endpoint instead.',
|
|
151
138
|
method: 'POST',
|
|
152
139
|
pathTemplate: '/partners/transactions/{id}/assign-to-bills-invoices',
|
|
153
|
-
|
|
140
|
+
requiresUserAuth: true,
|
|
141
|
+
readOnly: false,
|
|
142
|
+
destructive: false,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'COUNT_split_transaction',
|
|
146
|
+
title: 'Split Transaction',
|
|
147
|
+
description: 'Split an existing transaction into a parent row plus child rows before assigning part of the amount to a bill or invoice. URL `{id}` is the transaction UUID from `list_transactions`. Body mirrors the COUNT UI split flow: `{ forAttachment?: boolean, splitASplit?: boolean, withCaution?: boolean, parent?: { categoryAccountUuid, amount?, assignThis?, originalAmount?, type? }, splits?: [{ categoryAccountUuid, amount }] }`. Use `categoryAccountUuid` values from `list_accounts` (cannot target a system control account). Transfer and deposit transactions cannot be split. Reconciled transactions require `withCaution: true`. **400s if the transaction is already linked to a bill or invoice** — unassign it first. **Omitting `splits` (or sending `[]`) does not no-op — it UN-SPLITS an already-split transaction**, permanently destroying every existing split-child row and restoring the parent to its original un-split amount; never send an empty `splits` array unless that is the intent. After splitting, assign the intended child row with `COUNT_assign_transaction_to_bills_invoices`.',
|
|
148
|
+
method: 'PUT',
|
|
149
|
+
pathTemplate: '/partners/transactions/{id}/split',
|
|
154
150
|
requiresUserAuth: true,
|
|
155
151
|
readOnly: false,
|
|
156
152
|
destructive: false,
|
|
@@ -161,18 +157,36 @@ const tools = [
|
|
|
161
157
|
description: 'Delete a transaction by external UUID.',
|
|
162
158
|
method: 'DELETE',
|
|
163
159
|
pathTemplate: '/partners/transactions/{id}',
|
|
164
|
-
inputSchema: idInputSchema,
|
|
165
160
|
requiresUserAuth: true,
|
|
166
161
|
readOnly: false,
|
|
167
162
|
destructive: true,
|
|
168
163
|
},
|
|
164
|
+
{
|
|
165
|
+
name: 'COUNT_bulk_exclude_transactions',
|
|
166
|
+
title: 'Bulk Exclude Transactions',
|
|
167
|
+
description: 'Exclude or un-exclude up to 100 transactions in one call by external UUID (`body.transactionUuids`, `body.excluded: boolean`). Excluding hides a transaction from the ledger without deleting it — preserves the audit trail and survives bank-feed re-sync, unlike `COUNT_delete_transaction`. This is a per-row partial-success operation, same as `COUNT_bulk_change_transaction_category`: an unresolvable UUID, or a transaction that is reviewed/reconciled/pending/attached to a bill/invoice/transfer/deposit, becomes one entry in the response `failures` array instead of failing the whole batch — exclude only unreviewed transactions to avoid failures. Response: `{ updatedTransactions, successCount, failedCount, failures: [{ transactionUuid, reasons: string[] }] }`. To exclude by date range, first call `COUNT_list_transactions` with `startDate`/`endDate` (and `reviewed: false`) to collect UUIDs, then pass them here.',
|
|
168
|
+
method: 'PATCH',
|
|
169
|
+
pathTemplate: '/partners/transactions/exclude-bulk',
|
|
170
|
+
requiresUserAuth: true,
|
|
171
|
+
readOnly: false,
|
|
172
|
+
destructive: false,
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'COUNT_bulk_change_transaction_category',
|
|
176
|
+
title: 'Bulk Change Transaction Category',
|
|
177
|
+
description: 'Categorize (or uncategorize) up to 100 EXISTING transactions in one call. Body: `categoryAccountUuid` (a category account UUID from `list_accounts`, or `null` to uncategorize) and `transactionUuids` (array). This is a per-row partial-success operation, same as `COUNT_bulk_exclude_transactions`: an unresolvable UUID, or a transaction that is reviewed/reconciled/pending/attached to a bill/invoice/transfer/deposit, becomes one entry in the response `failures` array rather than failing the whole batch. Response: `{ updatedTransactions, successCount, failedCount, failures: [{ transactionUuid, reasons: string[] }] }`. For NEW transactions, pass `categoryAccountUuid` directly to `COUNT_create_transaction`/`COUNT_bulk_create_transactions` instead — no follow-up call needed. For a single existing transaction, `COUNT_change_transaction_category` is equivalent and returns the full updated row.',
|
|
178
|
+
method: 'PATCH',
|
|
179
|
+
pathTemplate: '/partners/transactions/change-category-bulk',
|
|
180
|
+
requiresUserAuth: true,
|
|
181
|
+
readOnly: false,
|
|
182
|
+
destructive: false,
|
|
183
|
+
},
|
|
169
184
|
{
|
|
170
185
|
name: 'COUNT_list_account_sub_types',
|
|
171
186
|
title: 'List Account Sub-Types',
|
|
172
187
|
description: 'List every chart-of-accounts sub-type available in COUNT (global catalog — the same integer ids apply in every workspace). **Call this before `COUNT_create_account`** to discover the correct `subTypeId`; e.g. set `query.type` to `"Liabilities"` and pick the row whose `name` is `Credit Card`. Optional `query.type`: one of `Assets`, `Liabilities`, `Equity`, `Income`, `Expenses` (case-sensitive, plural). Each row returns `id` (pass as `subTypeId` on create), `type`, `name`, `description`, and `anchorTier`. **Never guess or sequentially probe subType ids** — they are sparse and not predictable from other ids.',
|
|
173
188
|
method: 'GET',
|
|
174
189
|
pathTemplate: '/partners/account-sub-types',
|
|
175
|
-
inputSchema: queryInputSchema,
|
|
176
190
|
requiresUserAuth: true,
|
|
177
191
|
readOnly: true,
|
|
178
192
|
destructive: false,
|
|
@@ -180,10 +194,9 @@ const tools = [
|
|
|
180
194
|
{
|
|
181
195
|
name: 'COUNT_list_accounts',
|
|
182
196
|
title: 'List Chart Of Accounts',
|
|
183
|
-
description: 'List chart of accounts for the authenticated COUNT workspace. When you need a `subTypeId` for a **new** account and no similar account exists yet, prefer `COUNT_list_account_sub_types` instead of guessing from sparse ids. Optional filters (pass under `query`): `type` must be one of `Assets`, `Liabilities`, `Equity`, `Income`, `Expenses` (case-sensitive, plural — singular forms like "Asset" are rejected); `subTypeId` is a positive integer; `search` is a substring matched against account name / number; boolean-string filters `inactive`, `includeBalances`, `includeHidden`, `includeHiddenAccounts`, `is1099Box`, `notAssignedToReporter`, `onlyCategoryAccounts`, `includeDeleteMeta` accept `"true"` / `"false"`. Existing rows include `subType.id` — you may reuse that integer when creating another account in the same bucket.',
|
|
197
|
+
description: 'List chart of accounts for the authenticated COUNT workspace. When you need a `subTypeId` for a **new** account and no similar account exists yet, prefer `COUNT_list_account_sub_types` instead of guessing from sparse ids. Optional filters (pass under `query`): `type` must be one of `Assets`, `Liabilities`, `Equity`, `Income`, `Expenses` (case-sensitive, plural — singular forms like "Asset" are rejected); `subTypeId` is a positive integer; `search` is a substring matched against account name / number; boolean-string filters `inactive`, `includeBalances`, `includeHidden`, `includeHiddenAccounts`, `is1099Box`, `notAssignedToReporter`, `onlyCategoryAccounts`, `includeDeleteMeta` accept `"true"` / `"false"`. Each row includes `editable` (`false` for system/control/connected accounts). When `includeDeleteMeta=true`, each row also includes `canDelete` and `deleteBlockedReason` (`NOT_EDITABLE`, `HAS_JOURNAL_ENTRIES`, `HAS_SUB_ACCOUNTS`, `HAS_INVOICE_PRODUCTS`, `HAS_PAYROLL_MAPPINGS`) so you can tell whether update/delete will succeed before calling those tools. Existing rows include `subType.id` — you may reuse that integer when creating another account in the same bucket.',
|
|
184
198
|
method: 'GET',
|
|
185
199
|
pathTemplate: '/partners/chart-of-accounts',
|
|
186
|
-
inputSchema: queryInputSchema,
|
|
187
200
|
requiresUserAuth: true,
|
|
188
201
|
readOnly: true,
|
|
189
202
|
destructive: false,
|
|
@@ -194,7 +207,16 @@ const tools = [
|
|
|
194
207
|
description: 'Create a chart-of-accounts entry. **Always resolve `subTypeId` first — never guess or probe ids.** Preferred: `COUNT_list_account_sub_types` (filter `query.type`, pick the matching `name`, use its `id`). Fallback: `COUNT_list_accounts` with `query.type` and reuse `subType.id` from an existing row in that bucket. Required body: `name` (string) and `subTypeId` (integer from list_account_sub_types or list_accounts). Optional body: `accountNumber`, `currency` (defaults to the workspace currency), `description`, `color` (hex), `parentAccountId` (numeric id of an existing parent account — sub-accounts inherit the parent\'s `type` / `currency` / `status` and a sub-account cannot itself have sub-accounts), `institutionId`, `taxes: number[]` (internal numeric tax ids — required for NZ workspaces), `status` ("active" | "inactive"). The high-level `type` (Assets/Liabilities/Equity/Income/Expenses) is derived from `subTypeId` server-side; do not send it. If creation fails, tell the user COUNT could not create the account and include the `requestId` when present — **never** quote stack traces, source file paths, line numbers, or internal database field names in user-visible text.',
|
|
195
208
|
method: 'POST',
|
|
196
209
|
pathTemplate: '/partners/chart-of-accounts',
|
|
197
|
-
|
|
210
|
+
requiresUserAuth: true,
|
|
211
|
+
readOnly: false,
|
|
212
|
+
destructive: false,
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: 'COUNT_bulk_create_accounts',
|
|
216
|
+
title: 'Bulk Create Accounts',
|
|
217
|
+
description: 'Create up to 100 chart-of-accounts entries in a single call. Body: `{ "accounts": [<row>, ...] }` where each `<row>` uses the EXACT same shape as `COUNT_create_account` (required `name` and `subTypeId`; optional `accountNumber`, `currency`, `description`, `color`, `parentAccountId`, `institutionId`, `taxes`, `status`). **Partial-success contract**: each row runs in its own DB transaction; one row failing never rolls back another row\'s writes. Response envelope: `{ "successCount": N, "errorCount": M, "results": [{ "index": 0, "success": true, "account": {...} } | { "index": 1, "success": false, "error": "..." }, ...] }` — read `errorCount` first; if non-zero, iterate `results` and only retry the rows where `success: false`. The HTTP status is always `201` when the batch was accepted, even if all rows failed. **Cap**: 100 rows per call. **Recommended batch size**: ~25 rows for migrations. **Complete the full chart of accounts before importing bills or transactions** — accounts with journal entries cannot be deleted (`deleteBlockedReason: HAS_JOURNAL_ENTRIES`); use `COUNT_update_account` with `status: inactive` instead.',
|
|
218
|
+
method: 'POST',
|
|
219
|
+
pathTemplate: '/partners/chart-of-accounts/bulk',
|
|
198
220
|
requiresUserAuth: true,
|
|
199
221
|
readOnly: false,
|
|
200
222
|
destructive: false,
|
|
@@ -205,7 +227,6 @@ const tools = [
|
|
|
205
227
|
description: 'Update a chart-of-accounts entry by external UUID. Pass only the fields you want to change. Editable: `name`, `accountNumber`, `description`, `color`, `status` ("active" | "inactive"), `subTypeId` (must keep the same high-level `type` — switching a Bank account into an Income sub-type is rejected), `parentAccountId` (set to a valid parent id to nest, or pass `isChildAccount: false` to detach), `connectionSyncEnabled` (only meaningful on connected feed accounts). Do not send `type` (derived from `subTypeId`), `teamId`, `connectionId`, or `systemCreated` — they are stripped. System / non-editable accounts (e.g. payroll defaults) accept only a small allowlist of cosmetic fields plus name on physical accounts; expect a 403 if you try to edit a protected field. An empty body returns 400.',
|
|
206
228
|
method: 'PATCH',
|
|
207
229
|
pathTemplate: '/partners/chart-of-accounts/{id}',
|
|
208
|
-
inputSchema: idBodyInputSchema,
|
|
209
230
|
requiresUserAuth: true,
|
|
210
231
|
readOnly: false,
|
|
211
232
|
destructive: false,
|
|
@@ -213,10 +234,9 @@ const tools = [
|
|
|
213
234
|
{
|
|
214
235
|
name: 'COUNT_delete_account',
|
|
215
236
|
title: 'Delete Account',
|
|
216
|
-
description: 'Delete a chart of accounts entry by external UUID.',
|
|
237
|
+
description: 'Delete a chart of accounts entry by external UUID. Partner-created accounts are editable and deletable until they have journal entries, sub-accounts, invoice products, or payroll mappings. If delete fails because the account has journal entries, use `COUNT_update_account` with `status: inactive` instead. Call `COUNT_list_accounts` with `query.includeDeleteMeta: "true"` to read `canDelete` and `deleteBlockedReason` before attempting delete.',
|
|
217
238
|
method: 'DELETE',
|
|
218
239
|
pathTemplate: '/partners/chart-of-accounts/{id}',
|
|
219
|
-
inputSchema: idInputSchema,
|
|
220
240
|
requiresUserAuth: true,
|
|
221
241
|
readOnly: false,
|
|
222
242
|
destructive: true,
|
|
@@ -227,7 +247,6 @@ const tools = [
|
|
|
227
247
|
description: 'List vendors for the authenticated COUNT workspace.',
|
|
228
248
|
method: 'GET',
|
|
229
249
|
pathTemplate: '/partners/vendors',
|
|
230
|
-
inputSchema: queryInputSchema,
|
|
231
250
|
requiresUserAuth: true,
|
|
232
251
|
readOnly: true,
|
|
233
252
|
destructive: false,
|
|
@@ -238,7 +257,6 @@ const tools = [
|
|
|
238
257
|
description: 'Create a vendor.',
|
|
239
258
|
method: 'POST',
|
|
240
259
|
pathTemplate: '/partners/vendors',
|
|
241
|
-
inputSchema: bodyInputSchema,
|
|
242
260
|
requiresUserAuth: true,
|
|
243
261
|
readOnly: false,
|
|
244
262
|
destructive: false,
|
|
@@ -249,7 +267,6 @@ const tools = [
|
|
|
249
267
|
description: 'Update a vendor by external UUID.',
|
|
250
268
|
method: 'PATCH',
|
|
251
269
|
pathTemplate: '/partners/vendors/{id}',
|
|
252
|
-
inputSchema: idBodyInputSchema,
|
|
253
270
|
requiresUserAuth: true,
|
|
254
271
|
readOnly: false,
|
|
255
272
|
destructive: false,
|
|
@@ -260,7 +277,6 @@ const tools = [
|
|
|
260
277
|
description: 'Delete a vendor by external UUID.',
|
|
261
278
|
method: 'DELETE',
|
|
262
279
|
pathTemplate: '/partners/vendors/{id}',
|
|
263
|
-
inputSchema: idInputSchema,
|
|
264
280
|
requiresUserAuth: true,
|
|
265
281
|
readOnly: false,
|
|
266
282
|
destructive: true,
|
|
@@ -271,7 +287,6 @@ const tools = [
|
|
|
271
287
|
description: 'List customers for the authenticated COUNT workspace.',
|
|
272
288
|
method: 'GET',
|
|
273
289
|
pathTemplate: '/partners/customers',
|
|
274
|
-
inputSchema: queryInputSchema,
|
|
275
290
|
requiresUserAuth: true,
|
|
276
291
|
readOnly: true,
|
|
277
292
|
destructive: false,
|
|
@@ -282,7 +297,6 @@ const tools = [
|
|
|
282
297
|
description: 'Get a customer by external UUID.',
|
|
283
298
|
method: 'GET',
|
|
284
299
|
pathTemplate: '/partners/customers/{id}',
|
|
285
|
-
inputSchema: idInputSchema,
|
|
286
300
|
requiresUserAuth: true,
|
|
287
301
|
readOnly: true,
|
|
288
302
|
destructive: false,
|
|
@@ -293,7 +307,6 @@ const tools = [
|
|
|
293
307
|
description: 'Create a customer. Required body: `customer` (business or person name). Optional body: `email`, `mainPhone`, `website`, `notes`, `status` (`active` | `inactive`), `paymentTerm`, `taxNumber`, `taxAutoCalculate`, `taxExcluded`, `taxes` (numeric tax ids), `billingAddress`, `shippingAddress`, `contacts: [{ firstName?, lastName?, email?, phone?, isPrimary? }]`. Returns 201 with the created customer; `id` in the response is the external UUID.',
|
|
294
308
|
method: 'POST',
|
|
295
309
|
pathTemplate: '/partners/customers',
|
|
296
|
-
inputSchema: bodyInputSchema,
|
|
297
310
|
requiresUserAuth: true,
|
|
298
311
|
readOnly: false,
|
|
299
312
|
destructive: false,
|
|
@@ -304,7 +317,6 @@ const tools = [
|
|
|
304
317
|
description: 'Update a customer by external UUID.',
|
|
305
318
|
method: 'PUT',
|
|
306
319
|
pathTemplate: '/partners/customers/{id}',
|
|
307
|
-
inputSchema: idBodyInputSchema,
|
|
308
320
|
requiresUserAuth: true,
|
|
309
321
|
readOnly: false,
|
|
310
322
|
destructive: false,
|
|
@@ -315,7 +327,6 @@ const tools = [
|
|
|
315
327
|
description: 'Create up to 100 customers in a single call. Body: `{ "customers": [<row>, ...] }` where each `<row>` uses the EXACT same shape as `COUNT_create_customer` (required `customer`; optional `email`, `mainPhone`, `website`, `notes`, `status`, `paymentTerm`, `taxNumber`, `taxAutoCalculate`, `taxExcluded`, `taxes`, `billingAddress`, `shippingAddress`, `contacts`). **Partial-success contract**: each row runs in its own DB transaction; one row failing never rolls back another row\'s writes. Response envelope: `{ "successCount": N, "errorCount": M, "results": [{ "index": 0, "success": true, "customer": {...} } | { "index": 1, "success": false, "error": "..." }, ...] }` — read `errorCount` first; if non-zero, iterate `results` and only retry the rows where `success: false`. The HTTP status is always `201` when the batch was accepted, even if all rows failed. **Cap**: 100 rows per call. **Recommended batch size**: ~25 rows for large migrations (e.g. importing customers from an external billing system).',
|
|
316
328
|
method: 'POST',
|
|
317
329
|
pathTemplate: '/partners/customers/bulk',
|
|
318
|
-
inputSchema: bodyInputSchema,
|
|
319
330
|
requiresUserAuth: true,
|
|
320
331
|
readOnly: false,
|
|
321
332
|
destructive: false,
|
|
@@ -326,7 +337,6 @@ const tools = [
|
|
|
326
337
|
description: 'Update up to 100 customers in a single call. Body: `{ "customers": [{ "uuid": "<external COUNT customer id>", ...fields }] }` where each row must include `uuid` plus the fields to patch (same writable fields as `COUNT_update_customer`, e.g. `email`, `mainPhone`, `website`, `notes`, `status`, `paymentTerm`, `billingAddress`, `shippingAddress`, `contacts`). **Partial-success contract**: each row is updated independently; one row failing never rolls back another row\'s writes. Response envelope: `{ "successCount": N, "errorCount": M, "results": [{ "index": 0, "success": true, "customer": {...} } | { "index": 1, "success": false, "error": "..." }, ...] }`. The HTTP status is always `201` when the batch was accepted. **Recommended batch size**: ~25 rows for backfilling email/phone on migrated customers.',
|
|
327
338
|
method: 'PATCH',
|
|
328
339
|
pathTemplate: '/partners/customers/bulk',
|
|
329
|
-
inputSchema: bodyInputSchema,
|
|
330
340
|
requiresUserAuth: true,
|
|
331
341
|
readOnly: false,
|
|
332
342
|
destructive: false,
|
|
@@ -337,7 +347,6 @@ const tools = [
|
|
|
337
347
|
description: 'Delete a customer by external UUID.',
|
|
338
348
|
method: 'DELETE',
|
|
339
349
|
pathTemplate: '/partners/customers/{id}',
|
|
340
|
-
inputSchema: idInputSchema,
|
|
341
350
|
requiresUserAuth: true,
|
|
342
351
|
readOnly: false,
|
|
343
352
|
destructive: true,
|
|
@@ -348,7 +357,6 @@ const tools = [
|
|
|
348
357
|
description: 'List people records for the authenticated COUNT workspace.',
|
|
349
358
|
method: 'GET',
|
|
350
359
|
pathTemplate: '/partners/people',
|
|
351
|
-
inputSchema: queryInputSchema,
|
|
352
360
|
requiresUserAuth: true,
|
|
353
361
|
readOnly: true,
|
|
354
362
|
destructive: false,
|
|
@@ -359,7 +367,6 @@ const tools = [
|
|
|
359
367
|
description: 'Get a people record by external UUID.',
|
|
360
368
|
method: 'GET',
|
|
361
369
|
pathTemplate: '/partners/people/{id}',
|
|
362
|
-
inputSchema: idInputSchema,
|
|
363
370
|
requiresUserAuth: true,
|
|
364
371
|
readOnly: true,
|
|
365
372
|
destructive: false,
|
|
@@ -370,7 +377,6 @@ const tools = [
|
|
|
370
377
|
description: 'List products and services for the authenticated COUNT workspace.',
|
|
371
378
|
method: 'GET',
|
|
372
379
|
pathTemplate: '/partners/products',
|
|
373
|
-
inputSchema: queryInputSchema,
|
|
374
380
|
requiresUserAuth: true,
|
|
375
381
|
readOnly: true,
|
|
376
382
|
destructive: false,
|
|
@@ -381,7 +387,6 @@ const tools = [
|
|
|
381
387
|
description: 'Get a product or service by external UUID.',
|
|
382
388
|
method: 'GET',
|
|
383
389
|
pathTemplate: '/partners/products/{id}',
|
|
384
|
-
inputSchema: idInputSchema,
|
|
385
390
|
requiresUserAuth: true,
|
|
386
391
|
readOnly: true,
|
|
387
392
|
destructive: false,
|
|
@@ -389,10 +394,9 @@ const tools = [
|
|
|
389
394
|
{
|
|
390
395
|
name: 'COUNT_create_product',
|
|
391
396
|
title: 'Create Product',
|
|
392
|
-
description: 'Create a product or service.',
|
|
397
|
+
description: 'Create a product or service. Use `categoryAccountUuid` and `purchaseCategoryAccountUuid` (from `list_accounts`) for income/purchase category accounts — do not pass UUID-shaped values in `categoryAccountId`/`purchaseCategoryAccountId`. Use `taxUuids` (from `list_taxes`) for taxes.',
|
|
393
398
|
method: 'POST',
|
|
394
399
|
pathTemplate: '/partners/products',
|
|
395
|
-
inputSchema: bodyInputSchema,
|
|
396
400
|
requiresUserAuth: true,
|
|
397
401
|
readOnly: false,
|
|
398
402
|
destructive: false,
|
|
@@ -400,10 +404,9 @@ const tools = [
|
|
|
400
404
|
{
|
|
401
405
|
name: 'COUNT_update_product',
|
|
402
406
|
title: 'Update Product',
|
|
403
|
-
description: 'Update a product or service by external UUID.',
|
|
407
|
+
description: 'Update a product or service by external UUID. Use `categoryAccountUuid`, `purchaseCategoryAccountUuid`, and `taxUuids` for account/tax references (see `COUNT_create_product`).',
|
|
404
408
|
method: 'PATCH',
|
|
405
409
|
pathTemplate: '/partners/products/{id}',
|
|
406
|
-
inputSchema: idBodyInputSchema,
|
|
407
410
|
requiresUserAuth: true,
|
|
408
411
|
readOnly: false,
|
|
409
412
|
destructive: false,
|
|
@@ -414,7 +417,6 @@ const tools = [
|
|
|
414
417
|
description: 'Delete a product or service by external UUID.',
|
|
415
418
|
method: 'DELETE',
|
|
416
419
|
pathTemplate: '/partners/products/{id}',
|
|
417
|
-
inputSchema: idInputSchema,
|
|
418
420
|
requiresUserAuth: true,
|
|
419
421
|
readOnly: false,
|
|
420
422
|
destructive: true,
|
|
@@ -425,7 +427,6 @@ const tools = [
|
|
|
425
427
|
description: 'List tags for the authenticated COUNT workspace.',
|
|
426
428
|
method: 'GET',
|
|
427
429
|
pathTemplate: '/partners/tags',
|
|
428
|
-
inputSchema: queryInputSchema,
|
|
429
430
|
requiresUserAuth: true,
|
|
430
431
|
readOnly: true,
|
|
431
432
|
destructive: false,
|
|
@@ -436,7 +437,6 @@ const tools = [
|
|
|
436
437
|
description: 'Get a tag by external UUID.',
|
|
437
438
|
method: 'GET',
|
|
438
439
|
pathTemplate: '/partners/tags/{id}',
|
|
439
|
-
inputSchema: idInputSchema,
|
|
440
440
|
requiresUserAuth: true,
|
|
441
441
|
readOnly: true,
|
|
442
442
|
destructive: false,
|
|
@@ -447,7 +447,6 @@ const tools = [
|
|
|
447
447
|
description: 'Create a tag.',
|
|
448
448
|
method: 'POST',
|
|
449
449
|
pathTemplate: '/partners/tags',
|
|
450
|
-
inputSchema: bodyInputSchema,
|
|
451
450
|
requiresUserAuth: true,
|
|
452
451
|
readOnly: false,
|
|
453
452
|
destructive: false,
|
|
@@ -458,7 +457,6 @@ const tools = [
|
|
|
458
457
|
description: 'Update a tag by external UUID.',
|
|
459
458
|
method: 'PATCH',
|
|
460
459
|
pathTemplate: '/partners/tags/{id}',
|
|
461
|
-
inputSchema: idBodyInputSchema,
|
|
462
460
|
requiresUserAuth: true,
|
|
463
461
|
readOnly: false,
|
|
464
462
|
destructive: false,
|
|
@@ -469,7 +467,6 @@ const tools = [
|
|
|
469
467
|
description: 'Delete a tag by external UUID.',
|
|
470
468
|
method: 'DELETE',
|
|
471
469
|
pathTemplate: '/partners/tags/{id}',
|
|
472
|
-
inputSchema: idInputSchema,
|
|
473
470
|
requiresUserAuth: true,
|
|
474
471
|
readOnly: false,
|
|
475
472
|
destructive: true,
|
|
@@ -480,7 +477,6 @@ const tools = [
|
|
|
480
477
|
description: 'List tag groups for the authenticated COUNT workspace.',
|
|
481
478
|
method: 'GET',
|
|
482
479
|
pathTemplate: '/partners/tags/groups',
|
|
483
|
-
inputSchema: queryInputSchema,
|
|
484
480
|
requiresUserAuth: true,
|
|
485
481
|
readOnly: true,
|
|
486
482
|
destructive: false,
|
|
@@ -491,7 +487,6 @@ const tools = [
|
|
|
491
487
|
description: 'Get a tag group by external UUID.',
|
|
492
488
|
method: 'GET',
|
|
493
489
|
pathTemplate: '/partners/tags/groups/{id}',
|
|
494
|
-
inputSchema: idInputSchema,
|
|
495
490
|
requiresUserAuth: true,
|
|
496
491
|
readOnly: true,
|
|
497
492
|
destructive: false,
|
|
@@ -502,7 +497,6 @@ const tools = [
|
|
|
502
497
|
description: 'Create a tag group. Body: `name` (required, string, unique per workspace), `color` (optional string), and `tagUuids` (optional array of tag UUIDs from `list_tags`) — each tag may belong to at most one group, so passing a tag already in another group rejects the request with a 400. Send tag UUIDs (not numeric ids); the server resolves them to internal ids automatically.',
|
|
503
498
|
method: 'POST',
|
|
504
499
|
pathTemplate: '/partners/tags/groups',
|
|
505
|
-
inputSchema: bodyInputSchema,
|
|
506
500
|
requiresUserAuth: true,
|
|
507
501
|
readOnly: false,
|
|
508
502
|
destructive: false,
|
|
@@ -513,7 +507,6 @@ const tools = [
|
|
|
513
507
|
description: 'Update a tag group by external UUID. Body: optional `name`, `color`, and `tagUuids` (array of tag UUIDs from `list_tags`). When `tagUuids` is sent the group\'s membership is REPLACED with that exact set (existing tags not in the array are removed, new ones added); pass `[]` to clear all tags. A tag can only belong to one group at a time. Send tag UUIDs (not numeric ids); the server resolves them to internal ids automatically.',
|
|
514
508
|
method: 'PATCH',
|
|
515
509
|
pathTemplate: '/partners/tags/groups/{id}',
|
|
516
|
-
inputSchema: idBodyInputSchema,
|
|
517
510
|
requiresUserAuth: true,
|
|
518
511
|
readOnly: false,
|
|
519
512
|
destructive: false,
|
|
@@ -524,7 +517,6 @@ const tools = [
|
|
|
524
517
|
description: 'Delete a tag group by external UUID.',
|
|
525
518
|
method: 'DELETE',
|
|
526
519
|
pathTemplate: '/partners/tags/groups/{id}',
|
|
527
|
-
inputSchema: idInputSchema,
|
|
528
520
|
requiresUserAuth: true,
|
|
529
521
|
readOnly: false,
|
|
530
522
|
destructive: true,
|
|
@@ -535,7 +527,6 @@ const tools = [
|
|
|
535
527
|
description: 'List invoices for the authenticated COUNT workspace.',
|
|
536
528
|
method: 'GET',
|
|
537
529
|
pathTemplate: '/partners/invoices',
|
|
538
|
-
inputSchema: queryInputSchema,
|
|
539
530
|
requiresUserAuth: true,
|
|
540
531
|
readOnly: true,
|
|
541
532
|
destructive: false,
|
|
@@ -546,7 +537,6 @@ const tools = [
|
|
|
546
537
|
description: 'Get an invoice by external UUID.',
|
|
547
538
|
method: 'GET',
|
|
548
539
|
pathTemplate: '/partners/invoices/{id}',
|
|
549
|
-
inputSchema: idInputSchema,
|
|
550
540
|
requiresUserAuth: true,
|
|
551
541
|
readOnly: true,
|
|
552
542
|
destructive: false,
|
|
@@ -557,7 +547,6 @@ const tools = [
|
|
|
557
547
|
description: 'Create an invoice, credit memo, or estimate. Required body: `customerUuid` (from `list_customers`), `date` (YYYY-MM-DD), and `products: [{ productUuid | uuid, quantity, unitPrice, ... }]` (each line resolves a product UUID into the internal product id; `unitPrice` is per-unit in workspace currency). Optional body: `invoiceType` ("invoice" — default | "estimate" | "memo"), `invoiceNumber`, `dueDate` (YYYY-MM-DD), `currency` (defaults to workspace currency), `discount` + `discountDescription`, `notes`, `tagUuids: string[]` (replaces all tags), `appliedToInvoiceUuid` (only for `invoiceType: "memo"` — links the credit memo to the original invoice), `isDraft` (boolean — drafts skip approval / journals), `applyCredit` + `creditMemo: { id, amount }` (apply an existing memo), and recurring-template fields (`recurrencePattern`, `inAdvanceCreationDays`) when creating a recurring schedule via this endpoint. **Do not send numeric ids for `customer`/`products[].id`/`tags`/`appliedToInvoiceId`** — the partner middleware resolves UUIDs into them. Memos cannot be recurring; recurring memos return 400.',
|
|
558
548
|
method: 'POST',
|
|
559
549
|
pathTemplate: '/partners/invoices',
|
|
560
|
-
inputSchema: bodyInputSchema,
|
|
561
550
|
requiresUserAuth: true,
|
|
562
551
|
readOnly: false,
|
|
563
552
|
destructive: false,
|
|
@@ -570,7 +559,6 @@ const tools = [
|
|
|
570
559
|
'When the body is empty or contains internal-only or unknown fields, the response is still 200 with the unchanged invoice but includes a `_partnerWarnings: [{ field, reason, message }]` array describing each ignored field — read it before assuming the update succeeded.',
|
|
571
560
|
method: 'PATCH',
|
|
572
561
|
pathTemplate: '/partners/invoices/{id}',
|
|
573
|
-
inputSchema: idBodyInputSchema,
|
|
574
562
|
requiresUserAuth: true,
|
|
575
563
|
readOnly: false,
|
|
576
564
|
destructive: false,
|
|
@@ -581,7 +569,6 @@ const tools = [
|
|
|
581
569
|
description: 'Delete an invoice by external UUID.',
|
|
582
570
|
method: 'DELETE',
|
|
583
571
|
pathTemplate: '/partners/invoices/{id}',
|
|
584
|
-
inputSchema: idInputSchema,
|
|
585
572
|
requiresUserAuth: true,
|
|
586
573
|
readOnly: false,
|
|
587
574
|
destructive: true,
|
|
@@ -592,7 +579,6 @@ const tools = [
|
|
|
592
579
|
description: 'Approve a draft invoice by external UUID. Moves the invoice from `draft` → `approved`, posts the underlying journal entries, and makes the invoice eligible for `send`. Body is optional — pass nothing for the standard approval. Errors with 400 if the invoice is already approved, sent, or paid; not valid for `invoiceType: "memo"` drafts (use the regular update + send flow on memos).',
|
|
593
580
|
method: 'PATCH',
|
|
594
581
|
pathTemplate: '/partners/invoices/{id}/approve',
|
|
595
|
-
inputSchema: idOptionalBodyInputSchema,
|
|
596
582
|
requiresUserAuth: true,
|
|
597
583
|
readOnly: false,
|
|
598
584
|
destructive: false,
|
|
@@ -603,7 +589,6 @@ const tools = [
|
|
|
603
589
|
description: 'Send (or re-send) an approved invoice to its customer by external UUID. Optional body: `recipients: string[]` (override the customer\'s default email), `subject`, `message`, `attachPdf: boolean` (defaults to true), `cc: string[]`, `bcc: string[]`. The invoice must be approved first via `approve_invoice`; calling `send` on a draft returns 400. After a successful send the invoice transitions to `sent`/`unpaid` and becomes the canonical version the customer sees in the public link.',
|
|
604
590
|
method: 'POST',
|
|
605
591
|
pathTemplate: '/partners/invoices/{id}/send',
|
|
606
|
-
inputSchema: idOptionalBodyInputSchema,
|
|
607
592
|
requiresUserAuth: true,
|
|
608
593
|
readOnly: false,
|
|
609
594
|
destructive: false,
|
|
@@ -614,7 +599,6 @@ const tools = [
|
|
|
614
599
|
description: 'Get a public payment/view link for an invoice by external UUID.',
|
|
615
600
|
method: 'GET',
|
|
616
601
|
pathTemplate: '/partners/invoices/{id}/public-link',
|
|
617
|
-
inputSchema: idInputSchema,
|
|
618
602
|
requiresUserAuth: true,
|
|
619
603
|
readOnly: true,
|
|
620
604
|
destructive: false,
|
|
@@ -625,7 +609,6 @@ const tools = [
|
|
|
625
609
|
description: 'Get the audit log for an invoice by external UUID.',
|
|
626
610
|
method: 'GET',
|
|
627
611
|
pathTemplate: '/partners/invoices/{id}/audit-log',
|
|
628
|
-
inputSchema: idInputSchema,
|
|
629
612
|
requiresUserAuth: true,
|
|
630
613
|
readOnly: true,
|
|
631
614
|
destructive: false,
|
|
@@ -636,7 +619,6 @@ const tools = [
|
|
|
636
619
|
description: 'Attach documents to an invoice (or estimate / memo) by external UUID using already-hosted URLs — the COUNT server fetches each URL once and stores it as a regular invoice attachment. Body: `{ attachments: [{ url: string, title?: string }] }`. The URL must be publicly fetchable from the COUNT server (no signed-cookie / VPN-only links). For uploading raw bytes use the dedicated `/attachments/upload` multipart endpoint instead — that path is not exposed as an MCP tool because MCP tools cannot send multipart bodies.',
|
|
637
620
|
method: 'POST',
|
|
638
621
|
pathTemplate: '/partners/invoices/{id}/attachments',
|
|
639
|
-
inputSchema: idBodyInputSchema,
|
|
640
622
|
requiresUserAuth: true,
|
|
641
623
|
readOnly: false,
|
|
642
624
|
destructive: false,
|
|
@@ -647,7 +629,6 @@ const tools = [
|
|
|
647
629
|
description: 'Apply one or more credit memos to a single invoice by external UUID. Body: `{ creditMemos: [{ id: <invoice or memo UUID>, amount: <decimal> }, ...] }`. Each `id` accepts a UUID, a numeric id, or a numeric string — the partner middleware resolves them and asserts each memo belongs to the same workspace. The sum of `amount` values cannot exceed the open balance of the target invoice or the available balance on the memos; the request rolls back atomically if any memo is over-applied.',
|
|
648
630
|
method: 'PATCH',
|
|
649
631
|
pathTemplate: '/partners/invoices/{id}/apply-multiple-credit-to-invoice',
|
|
650
|
-
inputSchema: idBodyInputSchema,
|
|
651
632
|
requiresUserAuth: true,
|
|
652
633
|
readOnly: false,
|
|
653
634
|
destructive: false,
|
|
@@ -658,7 +639,6 @@ const tools = [
|
|
|
658
639
|
description: 'Apply a single credit memo (the URL `id`) across multiple target invoices in one call. Body: `{ invoices: [{ id: <invoice UUID or numeric id>, amount: <decimal> }, ...] }`. The URL `id` is the credit memo to draw from; each entry in `invoices` is a target invoice plus the dollar amount of the memo to apply to it. Total applied amount cannot exceed the memo\'s remaining balance. The partner middleware resolves UUIDs to numeric ids and rejects cross-workspace references with 404.',
|
|
659
640
|
method: 'PATCH',
|
|
660
641
|
pathTemplate: '/partners/invoices/{id}/apply-credit-to-multiple-invoices',
|
|
661
|
-
inputSchema: idBodyInputSchema,
|
|
662
642
|
requiresUserAuth: true,
|
|
663
643
|
readOnly: false,
|
|
664
644
|
destructive: false,
|
|
@@ -669,7 +649,6 @@ const tools = [
|
|
|
669
649
|
description: 'Remove a previously-applied credit memo from an invoice by external UUID. Body: `{ memoId: <credit memo UUID or numeric id> }`. The memo\'s balance is restored and the target invoice\'s open balance increases by the unapplied amount. 404 if the memo isn\'t currently applied to this invoice.',
|
|
670
650
|
method: 'PATCH',
|
|
671
651
|
pathTemplate: '/partners/invoices/{id}/remove-credit',
|
|
672
|
-
inputSchema: idBodyInputSchema,
|
|
673
652
|
requiresUserAuth: true,
|
|
674
653
|
readOnly: false,
|
|
675
654
|
destructive: false,
|
|
@@ -680,7 +659,6 @@ const tools = [
|
|
|
680
659
|
description: 'Remove a previously-applied transaction payment from an invoice by external UUID. Body: `{ transactionId: <transaction UUID from list_transactions>, withCaution?: boolean }`. Restores the invoice open balance and unlinks the transaction from Accounts Receivable. Manual payment links only — automated Stripe links may not be removable via this endpoint.',
|
|
681
660
|
method: 'PATCH',
|
|
682
661
|
pathTemplate: '/partners/invoices/{id}/remove-transaction',
|
|
683
|
-
inputSchema: idBodyInputSchema,
|
|
684
662
|
requiresUserAuth: true,
|
|
685
663
|
readOnly: false,
|
|
686
664
|
destructive: false,
|
|
@@ -691,7 +669,6 @@ const tools = [
|
|
|
691
669
|
description: 'List recurring invoice templates for the authenticated COUNT workspace.',
|
|
692
670
|
method: 'GET',
|
|
693
671
|
pathTemplate: '/partners/recurring-invoice-templates',
|
|
694
|
-
inputSchema: queryInputSchema,
|
|
695
672
|
requiresUserAuth: true,
|
|
696
673
|
readOnly: true,
|
|
697
674
|
destructive: false,
|
|
@@ -702,7 +679,6 @@ const tools = [
|
|
|
702
679
|
description: 'Get a recurring invoice template by external UUID.',
|
|
703
680
|
method: 'GET',
|
|
704
681
|
pathTemplate: '/partners/recurring-invoice-templates/{id}',
|
|
705
|
-
inputSchema: idInputSchema,
|
|
706
682
|
requiresUserAuth: true,
|
|
707
683
|
readOnly: true,
|
|
708
684
|
destructive: false,
|
|
@@ -710,10 +686,9 @@ const tools = [
|
|
|
710
686
|
{
|
|
711
687
|
name: 'COUNT_create_recurring_invoice_template',
|
|
712
688
|
title: 'Create Recurring Invoice Template',
|
|
713
|
-
description: 'Create a recurring invoice template. Same body shape as `create_invoice` (`customerUuid`, `products`, etc.) PLUS a required `recurrencePattern`
|
|
689
|
+
description: 'Create a recurring invoice template. Same body shape as `create_invoice` (`customerUuid`, `products`, etc.) PLUS a required `recurrencePattern` string cadence (daily, weekly, biweekly, monthly, quarterly, or yearly). Optional `inAdvanceCreationDays` controls how many days before each scheduled date the next invoice instance is generated. `invoiceType` defaults to "invoice"; "memo" is rejected (credit memos cannot recur). `isDraft` defaults to true so the template is paused until you explicitly resume it via `resume_recurring_invoice_template`.',
|
|
714
690
|
method: 'POST',
|
|
715
691
|
pathTemplate: '/partners/recurring-invoice-templates',
|
|
716
|
-
inputSchema: bodyInputSchema,
|
|
717
692
|
requiresUserAuth: true,
|
|
718
693
|
readOnly: false,
|
|
719
694
|
destructive: false,
|
|
@@ -724,7 +699,6 @@ const tools = [
|
|
|
724
699
|
description: 'Update a recurring invoice template by external UUID.',
|
|
725
700
|
method: 'PATCH',
|
|
726
701
|
pathTemplate: '/partners/recurring-invoice-templates/{id}',
|
|
727
|
-
inputSchema: idBodyInputSchema,
|
|
728
702
|
requiresUserAuth: true,
|
|
729
703
|
readOnly: false,
|
|
730
704
|
destructive: false,
|
|
@@ -735,7 +709,6 @@ const tools = [
|
|
|
735
709
|
description: 'Delete a recurring invoice template by external UUID.',
|
|
736
710
|
method: 'DELETE',
|
|
737
711
|
pathTemplate: '/partners/recurring-invoice-templates/{id}',
|
|
738
|
-
inputSchema: idInputSchema,
|
|
739
712
|
requiresUserAuth: true,
|
|
740
713
|
readOnly: false,
|
|
741
714
|
destructive: true,
|
|
@@ -746,7 +719,6 @@ const tools = [
|
|
|
746
719
|
description: 'Pause a recurring invoice template by external UUID.',
|
|
747
720
|
method: 'POST',
|
|
748
721
|
pathTemplate: '/partners/recurring-invoice-templates/{id}/pause',
|
|
749
|
-
inputSchema: idOptionalBodyInputSchema,
|
|
750
722
|
requiresUserAuth: true,
|
|
751
723
|
readOnly: false,
|
|
752
724
|
destructive: false,
|
|
@@ -757,7 +729,6 @@ const tools = [
|
|
|
757
729
|
description: 'Resume a recurring invoice template by external UUID.',
|
|
758
730
|
method: 'POST',
|
|
759
731
|
pathTemplate: '/partners/recurring-invoice-templates/{id}/resume',
|
|
760
|
-
inputSchema: idOptionalBodyInputSchema,
|
|
761
732
|
requiresUserAuth: true,
|
|
762
733
|
readOnly: false,
|
|
763
734
|
destructive: false,
|
|
@@ -765,10 +736,9 @@ const tools = [
|
|
|
765
736
|
{
|
|
766
737
|
name: 'COUNT_list_bills',
|
|
767
738
|
title: 'List Bills',
|
|
768
|
-
description: 'List vendor bills for the authenticated workspace.
|
|
739
|
+
description: 'List vendor bills for the authenticated workspace. Returns bill rows with `id` as the external UUID. Filter fields are documented on the `query` input schema.',
|
|
769
740
|
method: 'GET',
|
|
770
741
|
pathTemplate: '/partners/bills',
|
|
771
|
-
inputSchema: queryInputSchema,
|
|
772
742
|
requiresUserAuth: true,
|
|
773
743
|
readOnly: true,
|
|
774
744
|
destructive: false,
|
|
@@ -779,7 +749,6 @@ const tools = [
|
|
|
779
749
|
description: 'Get a single bill by external UUID. Returns the bill record with line items, attachments, payments, current approval/payment status, and the linked vendor. Note: this endpoint also returns soft-deleted bills, so check the `isDeleted` field on the response if you need to filter them out client-side.',
|
|
780
750
|
method: 'GET',
|
|
781
751
|
pathTemplate: '/partners/bills/{id}',
|
|
782
|
-
inputSchema: idInputSchema,
|
|
783
752
|
requiresUserAuth: true,
|
|
784
753
|
readOnly: true,
|
|
785
754
|
destructive: false,
|
|
@@ -790,7 +759,6 @@ const tools = [
|
|
|
790
759
|
description: 'Create a vendor bill (accounts payable). Required body: `vendorUuid` (vendor UUID from `list_vendors`), `date` (YYYY-MM-DD), `dueDate` (YYYY-MM-DD), and `lineItems: [{ categoryAccountUuid, description?, quantity, price, total?, taxes?, projectUuid?, customerUuid? }]` where `categoryAccountUuid` is the expense/category account UUID from `list_accounts`. Optional body: `billNumber`, `purchaseOrderNumber`, `notes`, `currency` (defaults to workspace currency), `attachments: [{ url, title? }]`, `tagUuids: string[]`, `projectUuid`. Do NOT send numeric `vendorId`, `categoryAccountId`, or `tags` — use UUID fields only. The created bill enters the `draft` state; call `approve_bill` to post journals and make it eligible for payment. Returns 201 with the bill, or a `{ statusCode, message }` error envelope on validation failure.',
|
|
791
760
|
method: 'POST',
|
|
792
761
|
pathTemplate: '/partners/bills',
|
|
793
|
-
inputSchema: bodyInputSchema,
|
|
794
762
|
requiresUserAuth: true,
|
|
795
763
|
readOnly: false,
|
|
796
764
|
destructive: false,
|
|
@@ -801,7 +769,6 @@ const tools = [
|
|
|
801
769
|
description: 'Update a bill by external UUID. Pass only the fields you want to change. Editable: `vendorUuid`, `date`, `dueDate`, `billNumber`, `purchaseOrderNumber`, `notes`, `currency`, `lineItems` (replaces all lines when provided; each line uses `categoryAccountUuid`, `quantity`, `price`, optional `projectUuid`, `customerUuid`), `tagUuids`, `projectUuid`, `attachments`. Do NOT send numeric `vendorId`, `categoryAccountId`, or `tags`. Approved/paid bills have a more restrictive editable set — expect 400 on date/line changes after approval; use `delete_bill` + recreate if you need a structural change post-approval.',
|
|
802
770
|
method: 'PATCH',
|
|
803
771
|
pathTemplate: '/partners/bills/{id}',
|
|
804
|
-
inputSchema: idBodyInputSchema,
|
|
805
772
|
requiresUserAuth: true,
|
|
806
773
|
readOnly: false,
|
|
807
774
|
destructive: false,
|
|
@@ -812,7 +779,6 @@ const tools = [
|
|
|
812
779
|
description: 'Delete a bill by external UUID. Soft-delete on draft bills; bills that have any payments applied (`paidAmount > 0`) cannot be deleted and return 400 — unapply payments first via the standard payment endpoints.',
|
|
813
780
|
method: 'DELETE',
|
|
814
781
|
pathTemplate: '/partners/bills/{id}',
|
|
815
|
-
inputSchema: idInputSchema,
|
|
816
782
|
requiresUserAuth: true,
|
|
817
783
|
readOnly: false,
|
|
818
784
|
destructive: true,
|
|
@@ -823,7 +789,6 @@ const tools = [
|
|
|
823
789
|
description: 'Approve a draft bill by external UUID. Posts the underlying journal entries (debit each line\'s expense account, credit Accounts Payable) and makes the bill eligible for payment. Body is optional. Errors with 400 if the bill is already approved or has no line items.',
|
|
824
790
|
method: 'POST',
|
|
825
791
|
pathTemplate: '/partners/bills/{id}/approve',
|
|
826
|
-
inputSchema: idOptionalBodyInputSchema,
|
|
827
792
|
requiresUserAuth: true,
|
|
828
793
|
readOnly: false,
|
|
829
794
|
destructive: false,
|
|
@@ -834,7 +799,6 @@ const tools = [
|
|
|
834
799
|
description: 'Apply one or more vendor credit memos toward an approved bill by external UUID. Body: `{ memosBills: [{ id: <vendor-memo bill UUID from list_bills with billType vendor_memo>, amount: <decimal> }, ...] }`. Each memo must belong to the same vendor as the target bill; total applied cannot exceed the bill open balance or memo available balance. Vendor memos are bill records with `billType: "vendor_memo"` — use their UUID as `id`.',
|
|
835
800
|
method: 'POST',
|
|
836
801
|
pathTemplate: '/partners/bills/{id}/apply-vendor-memos',
|
|
837
|
-
inputSchema: idBodyInputSchema,
|
|
838
802
|
requiresUserAuth: true,
|
|
839
803
|
readOnly: false,
|
|
840
804
|
destructive: false,
|
|
@@ -845,7 +809,6 @@ const tools = [
|
|
|
845
809
|
description: 'Remove a previously-applied transaction payment from a bill by external UUID. Body: `{ transactionId: <transaction UUID from list_transactions>, withCaution?: boolean }`. Restores the bill open balance and clears the transaction\'s bill link.',
|
|
846
810
|
method: 'POST',
|
|
847
811
|
pathTemplate: '/partners/bills/{id}/unassign-transaction',
|
|
848
|
-
inputSchema: idBodyInputSchema,
|
|
849
812
|
requiresUserAuth: true,
|
|
850
813
|
readOnly: false,
|
|
851
814
|
destructive: false,
|
|
@@ -856,7 +819,6 @@ const tools = [
|
|
|
856
819
|
description: 'List journal entries for the authenticated COUNT workspace.',
|
|
857
820
|
method: 'GET',
|
|
858
821
|
pathTemplate: '/partners/journal-entries',
|
|
859
|
-
inputSchema: queryInputSchema,
|
|
860
822
|
requiresUserAuth: true,
|
|
861
823
|
readOnly: true,
|
|
862
824
|
destructive: false,
|
|
@@ -867,7 +829,6 @@ const tools = [
|
|
|
867
829
|
description: 'Create a manual journal entry. Body: required `descriptionEntry` (memo), `date` (YYYY-MM-DD), and `lines` (array). Each line needs `accountUuid` (the `id`, `accUuid`, or `accountUuid` from `list_accounts`) plus exactly one of `amountDebit` or `amountCredit` (decimal numbers as strings or numbers — never both on the same line, never neither). Optional per-line: `descriptionLine`. Optional top-level: `refNumber`, `withCaution: true` to skip book-closeness checks (use sparingly). The server validates each account exists in this workspace before posting; manual entries can fail if any line\'s posting date falls within a reconciled period for that account.',
|
|
868
830
|
method: 'POST',
|
|
869
831
|
pathTemplate: '/partners/journal-entries',
|
|
870
|
-
inputSchema: bodyInputSchema,
|
|
871
832
|
requiresUserAuth: true,
|
|
872
833
|
readOnly: false,
|
|
873
834
|
destructive: false,
|
|
@@ -878,7 +839,6 @@ const tools = [
|
|
|
878
839
|
description: 'Create up to 100 manual journal entry postings in a single call. Body: `{ "journalEntries": [<posting>, ...] }` where each `<posting>` uses the EXACT same shape as `COUNT_create_journal_entry` (required `descriptionEntry`, `date`, `lines`; each line needs `accountUuid` + exactly one of `amountDebit` / `amountCredit`; optional per-line `descriptionLine`; optional top-level `refNumber`, `withCaution`). **Partial-success contract**: each posting runs in its own DB transaction; one bad posting never rolls back another posting\'s writes. Response envelope: `{ "successCount": N, "errorCount": M, "results": [{ "index": 0, "success": true, "journalEntry": [...lines] } | { "index": 1, "success": false, "error": "..." }, ...] }` — read `errorCount` first; if non-zero, iterate `results` and only retry the postings where `success: false`. The HTTP status is always `201` when the batch was accepted, even if all postings failed. **Cap**: 100 postings per call (split larger imports into multiple calls). **Recommended batch size**: ~25 postings for large historical imports; larger batches increase timeout risk. **Performance note**: account UUIDs are resolved in a SINGLE batched lookup across the whole batch, so a 100-posting × 10-line request issues one account query — bulk is strictly cheaper than calling `COUNT_create_journal_entry` 100 times. **Use cases**: replay manual postings from another GL, backfill accruals, ingest a CSV of journal entries. For a single posting, prefer `COUNT_create_journal_entry` — the response shape is simpler.',
|
|
879
840
|
method: 'POST',
|
|
880
841
|
pathTemplate: '/partners/journal-entries/bulk',
|
|
881
|
-
inputSchema: bodyInputSchema,
|
|
882
842
|
requiresUserAuth: true,
|
|
883
843
|
readOnly: false,
|
|
884
844
|
destructive: false,
|
|
@@ -886,10 +846,9 @@ const tools = [
|
|
|
886
846
|
{
|
|
887
847
|
name: 'COUNT_update_journal_entry',
|
|
888
848
|
title: 'Update Journal Entry',
|
|
889
|
-
description: 'Update a manually-created journal entry by external UUID.
|
|
849
|
+
description: 'Update a manually-created journal entry by external UUID. PATCH accepts partial bodies — send only the fields you want to change (`descriptionEntry`, `date`, `refNumber`, and/or the full replacement `lines` array). When `lines` is included, each line takes `accountUuid` and exactly one of `amountDebit`/`amountCredit`. Only manually-created entries (and Square integration entries) can be updated; system-generated journal entries from invoices, bills, payroll, etc. are read-only and return 400.',
|
|
890
850
|
method: 'PATCH',
|
|
891
851
|
pathTemplate: '/partners/journal-entries/{id}',
|
|
892
|
-
inputSchema: idBodyInputSchema,
|
|
893
852
|
requiresUserAuth: true,
|
|
894
853
|
readOnly: false,
|
|
895
854
|
destructive: false,
|
|
@@ -900,7 +859,6 @@ const tools = [
|
|
|
900
859
|
description: 'Delete a journal entry by external UUID.',
|
|
901
860
|
method: 'DELETE',
|
|
902
861
|
pathTemplate: '/partners/journal-entries/{id}',
|
|
903
|
-
inputSchema: idInputSchema,
|
|
904
862
|
requiresUserAuth: true,
|
|
905
863
|
readOnly: false,
|
|
906
864
|
destructive: true,
|
|
@@ -911,7 +869,6 @@ const tools = [
|
|
|
911
869
|
description: 'List tasks for the authenticated workspace. `query` filters that accept comma-separated tokens where each token is EITHER an external UUID OR a workspace-scoped numeric id (partner middleware resolves both): `statusId` (task statuses), `assigneeId` / `assignerId` / `createdById` (workspace user references), `projects` (project filter), `commentId` (single token only — passing multiple returns 400). Pass-through filters: `page`, `limit`, `orderBy`, `orderDirection`, `search` (ILIKE on task name), `customId`, `visibility` (`"firm-team"` | `"team-only"` | `"firm-only"` — defaults to `["firm-team","team-only"]` when omitted), `priority`, `overduesOnly`, `deadlineDate` / `createdAt` / `updatedAt` (date windows), `status` (string `task.status` column). The legacy filters `clients`, `openTaskOnly`, and `isForClosing` are always stripped server-side. Numeric internal foreign keys are removed from response rows.',
|
|
912
870
|
method: 'GET',
|
|
913
871
|
pathTemplate: '/partners/tasks',
|
|
914
|
-
inputSchema: queryInputSchema,
|
|
915
872
|
requiresUserAuth: true,
|
|
916
873
|
readOnly: true,
|
|
917
874
|
destructive: false,
|
|
@@ -922,7 +879,6 @@ const tools = [
|
|
|
922
879
|
description: 'Get a single task by external UUID. Default visibility is `["firm-team","team-only"]`; tasks created with `firm-only` visibility (notably system-generated INTERNAL_TASK rows) return 404 unless you explicitly pass `visibility=firm-only` under `query`.',
|
|
923
880
|
method: 'GET',
|
|
924
881
|
pathTemplate: '/partners/tasks/{id}',
|
|
925
|
-
inputSchema: idInputSchema,
|
|
926
882
|
requiresUserAuth: true,
|
|
927
883
|
readOnly: true,
|
|
928
884
|
destructive: false,
|
|
@@ -933,7 +889,6 @@ const tools = [
|
|
|
933
889
|
description: 'Create a task. Required body: `type` (string — the task type identifier). The following optional FK fields each accept EITHER an external UUID OR a workspace-scoped numeric id (partner middleware resolves both and verifies workspace scope): `assigneeId`, `statusId`, `onCompleteStatusId`, `onCompleteAssigneeId`, `projectId`, `billId`, `transactionId`, `taskListId`, `taskListTemplateId`. Other safe body fields: `name`, `description`, `priority`, `deadline` (YYYY-MM-DD), `customId`, `visibility`. `tags` accepts an array OR a JSON-encoded string — every element must be the same kind (all UUIDs or all positive integer ids); mixed inputs return 400. If `assigneeId` is omitted it defaults to the partner-acting user. INTERNAL_TASK rows are always created with `firm-only` visibility regardless of the `visibility` value you pass. The partner endpoint is JSON-only — multipart attachments are not supported.',
|
|
934
890
|
method: 'POST',
|
|
935
891
|
pathTemplate: '/partners/tasks',
|
|
936
|
-
inputSchema: bodyInputSchema,
|
|
937
892
|
requiresUserAuth: true,
|
|
938
893
|
readOnly: false,
|
|
939
894
|
destructive: false,
|
|
@@ -944,7 +899,6 @@ const tools = [
|
|
|
944
899
|
description: 'Update a task by external UUID. Pass only the fields you want to change; the same body shape as `create_task` applies. `tags` accepts either an array or a JSON-encoded string and replaces all tags atomically. UUID-resolvable optional FKs: `assigneeId`, `statusId`, `onCompleteStatusId`, `onCompleteAssigneeId`, `projectId`, `billId`, `transactionId`, `taskListId`, `taskListTemplateId` — each accepts a UUID or a workspace-scoped numeric id.',
|
|
945
900
|
method: 'PATCH',
|
|
946
901
|
pathTemplate: '/partners/tasks/{id}',
|
|
947
|
-
inputSchema: idBodyInputSchema,
|
|
948
902
|
requiresUserAuth: true,
|
|
949
903
|
readOnly: false,
|
|
950
904
|
destructive: false,
|
|
@@ -955,7 +909,6 @@ const tools = [
|
|
|
955
909
|
description: 'Delete a task by external UUID.',
|
|
956
910
|
method: 'DELETE',
|
|
957
911
|
pathTemplate: '/partners/tasks/{id}',
|
|
958
|
-
inputSchema: idInputSchema,
|
|
959
912
|
requiresUserAuth: true,
|
|
960
913
|
readOnly: false,
|
|
961
914
|
destructive: true,
|
|
@@ -966,7 +919,6 @@ const tools = [
|
|
|
966
919
|
description: 'List projects for the authenticated workspace. Soft-deleted projects are always excluded. `query` filters: `page` (default 1), `limit` (default 20), `search` (ILIKE on project name), `customerUuids` (comma-separated customer UUIDs — partner middleware resolves these into the internal `customers` filter), and `statusUuids` (comma-separated project-status UUIDs — discover them via `list_project_statuses`). The internal `customers`, `statusIds`, and `status` filters are stripped server-side; only the `*Uuids` variants take effect.',
|
|
967
920
|
method: 'GET',
|
|
968
921
|
pathTemplate: '/partners/projects',
|
|
969
|
-
inputSchema: queryInputSchema,
|
|
970
922
|
requiresUserAuth: true,
|
|
971
923
|
readOnly: true,
|
|
972
924
|
destructive: false,
|
|
@@ -977,7 +929,6 @@ const tools = [
|
|
|
977
929
|
description: 'List the project statuses available in the authenticated workspace. Returns each status with its name, color, ordering, and external UUID — use the returned UUID as `statusUuid` on `create_project` / `update_project`, or in `statusUuids` (CSV) on `list_projects`.',
|
|
978
930
|
method: 'GET',
|
|
979
931
|
pathTemplate: '/partners/projects/statuses',
|
|
980
|
-
inputSchema: queryInputSchema,
|
|
981
932
|
requiresUserAuth: true,
|
|
982
933
|
readOnly: true,
|
|
983
934
|
destructive: false,
|
|
@@ -988,7 +939,6 @@ const tools = [
|
|
|
988
939
|
description: 'Get a single project by external UUID. Soft-deleted projects return 404.',
|
|
989
940
|
method: 'GET',
|
|
990
941
|
pathTemplate: '/partners/projects/{id}',
|
|
991
|
-
inputSchema: idInputSchema,
|
|
992
942
|
requiresUserAuth: true,
|
|
993
943
|
readOnly: true,
|
|
994
944
|
destructive: false,
|
|
@@ -999,7 +949,6 @@ const tools = [
|
|
|
999
949
|
description: 'List the tasks attached to a project by external UUID. `query` filters: `page` (default 1), `limit` (default 20), `search` (ILIKE on task name). Returns the same partner-sanitized task envelope as `list_tasks`.',
|
|
1000
950
|
method: 'GET',
|
|
1001
951
|
pathTemplate: '/partners/projects/{id}/tasks',
|
|
1002
|
-
inputSchema: idInputSchema,
|
|
1003
952
|
requiresUserAuth: true,
|
|
1004
953
|
readOnly: true,
|
|
1005
954
|
destructive: false,
|
|
@@ -1010,7 +959,6 @@ const tools = [
|
|
|
1010
959
|
description: 'Create a project. Required body: non-empty `name`. Optional body: `customerUuid` (from `list_customers`; pass `null` or omit to leave the project uncustomered), `statusUuid` (from `list_project_statuses` — defaults to the workspace\'s default status if omitted), plus any safe project columns (e.g. `description`, `customId`, `startDate`, `endDate`). The numeric internal FKs `customerId`, `statusId`, and `teamId` are always stripped before the request is processed — use the `*Uuid` variants instead.',
|
|
1011
960
|
method: 'POST',
|
|
1012
961
|
pathTemplate: '/partners/projects',
|
|
1013
|
-
inputSchema: bodyInputSchema,
|
|
1014
962
|
requiresUserAuth: true,
|
|
1015
963
|
readOnly: false,
|
|
1016
964
|
destructive: false,
|
|
@@ -1021,7 +969,6 @@ const tools = [
|
|
|
1021
969
|
description: 'Update a project by external UUID. Pass only the fields you want to change. `customerUuid` accepts a UUID (set the customer), `null`/`""` (clear the customer), or omission (leave unchanged). `statusUuid` accepts a UUID (set the status) or omission (leave unchanged). The numeric `customerId`, `statusId`, and `teamId` fields are stripped server-side. If you pass `customId` matching the existing value it may be discarded silently.',
|
|
1022
970
|
method: 'PATCH',
|
|
1023
971
|
pathTemplate: '/partners/projects/{id}',
|
|
1024
|
-
inputSchema: idBodyInputSchema,
|
|
1025
972
|
requiresUserAuth: true,
|
|
1026
973
|
readOnly: false,
|
|
1027
974
|
destructive: false,
|
|
@@ -1032,7 +979,6 @@ const tools = [
|
|
|
1032
979
|
description: 'Delete a project by external UUID (soft delete).',
|
|
1033
980
|
method: 'DELETE',
|
|
1034
981
|
pathTemplate: '/partners/projects/{id}',
|
|
1035
|
-
inputSchema: idInputSchema,
|
|
1036
982
|
requiresUserAuth: true,
|
|
1037
983
|
readOnly: false,
|
|
1038
984
|
destructive: true,
|
|
@@ -1043,7 +989,6 @@ const tools = [
|
|
|
1043
989
|
description: 'List time entries for the authenticated workspace. Soft-deleted entries are always excluded. `query` filters: `page` (default 1), `limit` (default 50), and the comma-separated UUID filters `peopleUuids`, `projectUuids`, `customerUuids`, `productServiceUuids` (each resolved into its internal numeric filter by the partner middleware). Direct numeric filters (`people`, `projects`, `customers`, `productServices`) are stripped server-side; only the `*Uuids` variants take effect. Date window filter: both `startDate` AND `endDate` (YYYY-MM-DD) must be provided together for the `createdAt`-range filter to apply — passing only one is ignored.',
|
|
1044
990
|
method: 'GET',
|
|
1045
991
|
pathTemplate: '/partners/time-entries',
|
|
1046
|
-
inputSchema: queryInputSchema,
|
|
1047
992
|
requiresUserAuth: true,
|
|
1048
993
|
readOnly: true,
|
|
1049
994
|
destructive: false,
|
|
@@ -1054,7 +999,6 @@ const tools = [
|
|
|
1054
999
|
description: 'Get a single time entry by external UUID. Soft-deleted entries return 404.',
|
|
1055
1000
|
method: 'GET',
|
|
1056
1001
|
pathTemplate: '/partners/time-entries/{id}',
|
|
1057
|
-
inputSchema: idInputSchema,
|
|
1058
1002
|
requiresUserAuth: true,
|
|
1059
1003
|
readOnly: true,
|
|
1060
1004
|
destructive: false,
|
|
@@ -1065,7 +1009,6 @@ const tools = [
|
|
|
1065
1009
|
description: 'Create one or more time entry rows. Required body: `peopleUuid` (from `list_people` — must be present and non-empty on create; partner middleware resolves it into the internal `peopleId`) and `timeEntries: [{ date: "YYYY-MM-DD", minutes: <integer>, ... }]` (array of row objects). Per-row optional fields: `description`, `projectUuid` (resolves to the project; setting it auto-fills the matching customer), `customerUuid`, `productServiceUuid`, `billable`, `wage`. Daily cap: the sum of `minutes` across entries on the same calendar day for the same person cannot exceed 24h — the server returns 400 with the remaining-minutes if exceeded. The numeric `peopleId`, `projectId`, `customerId`, `productServiceId`, and `teamId` fields are stripped server-side; use the `*Uuid` variants.',
|
|
1066
1010
|
method: 'POST',
|
|
1067
1011
|
pathTemplate: '/partners/time-entries',
|
|
1068
|
-
inputSchema: bodyInputSchema,
|
|
1069
1012
|
requiresUserAuth: true,
|
|
1070
1013
|
readOnly: false,
|
|
1071
1014
|
destructive: false,
|
|
@@ -1076,7 +1019,6 @@ const tools = [
|
|
|
1076
1019
|
description: 'Update a time entry by external UUID. Pass only the fields you want to change. `peopleUuid` cannot be cleared on update (passing `null`/`""` returns 400). `projectUuid` / `customerUuid` / `productServiceUuid` each accept a UUID (set) or `null` (clear). Time entries that belong to a processed pay period are read-only and return 400.',
|
|
1077
1020
|
method: 'PATCH',
|
|
1078
1021
|
pathTemplate: '/partners/time-entries/{id}',
|
|
1079
|
-
inputSchema: idBodyInputSchema,
|
|
1080
1022
|
requiresUserAuth: true,
|
|
1081
1023
|
readOnly: false,
|
|
1082
1024
|
destructive: false,
|
|
@@ -1087,7 +1029,6 @@ const tools = [
|
|
|
1087
1029
|
description: 'Delete a time entry by external UUID (soft delete). Time entries that belong to a processed pay period cannot be deleted and return 400 — adjust the pay period first.',
|
|
1088
1030
|
method: 'DELETE',
|
|
1089
1031
|
pathTemplate: '/partners/time-entries/{id}',
|
|
1090
|
-
inputSchema: idInputSchema,
|
|
1091
1032
|
requiresUserAuth: true,
|
|
1092
1033
|
readOnly: false,
|
|
1093
1034
|
destructive: true,
|
|
@@ -1101,7 +1042,6 @@ const tools = [
|
|
|
1101
1042
|
description: 'List expense receipts (pending receipts) for the authenticated COUNT workspace.',
|
|
1102
1043
|
method: 'GET',
|
|
1103
1044
|
pathTemplate: '/partners/expense-receipts',
|
|
1104
|
-
inputSchema: queryInputSchema,
|
|
1105
1045
|
requiresUserAuth: true,
|
|
1106
1046
|
readOnly: true,
|
|
1107
1047
|
destructive: false,
|
|
@@ -1112,7 +1052,6 @@ const tools = [
|
|
|
1112
1052
|
description: 'List unmatched expense receipts (pending receipts) for the authenticated COUNT workspace.',
|
|
1113
1053
|
method: 'GET',
|
|
1114
1054
|
pathTemplate: '/partners/expense-receipts/unmatched',
|
|
1115
|
-
inputSchema: queryInputSchema,
|
|
1116
1055
|
requiresUserAuth: true,
|
|
1117
1056
|
readOnly: true,
|
|
1118
1057
|
destructive: false,
|
|
@@ -1123,7 +1062,6 @@ const tools = [
|
|
|
1123
1062
|
description: 'Create an expense receipt (pending receipt). MCP forwards JSON only; to attach a receipt image call the partner HTTP API directly as multipart/form-data with field `receipt`. Partner bodies use UUID fields such as accountUuid, categoryAccountUuid, optional expenseReportTypeUuid, vendorUuid, projectUuid, tagUuids, taxUuids — see COUNT Partner API docs. API responses omit receiptUrl by design.',
|
|
1124
1063
|
method: 'POST',
|
|
1125
1064
|
pathTemplate: '/partners/expense-receipts',
|
|
1126
|
-
inputSchema: bodyInputSchema,
|
|
1127
1065
|
requiresUserAuth: true,
|
|
1128
1066
|
readOnly: false,
|
|
1129
1067
|
destructive: false,
|
|
@@ -1134,7 +1072,6 @@ const tools = [
|
|
|
1134
1072
|
description: 'Update an expense receipt by external UUID. MCP forwards JSON only; to replace the receipt image use multipart field `receipt` on the partner HTTP API.',
|
|
1135
1073
|
method: 'PATCH',
|
|
1136
1074
|
pathTemplate: '/partners/expense-receipts/{id}',
|
|
1137
|
-
inputSchema: idBodyInputSchema,
|
|
1138
1075
|
requiresUserAuth: true,
|
|
1139
1076
|
readOnly: false,
|
|
1140
1077
|
destructive: false,
|
|
@@ -1145,7 +1082,6 @@ const tools = [
|
|
|
1145
1082
|
description: 'Delete an unmatched expense receipt by external UUID.',
|
|
1146
1083
|
method: 'DELETE',
|
|
1147
1084
|
pathTemplate: '/partners/expense-receipts/{id}',
|
|
1148
|
-
inputSchema: idInputSchema,
|
|
1149
1085
|
requiresUserAuth: true,
|
|
1150
1086
|
readOnly: false,
|
|
1151
1087
|
destructive: true,
|
|
@@ -1156,7 +1092,6 @@ const tools = [
|
|
|
1156
1092
|
description: 'Match an expense receipt to an expense transaction. Body uses transactionUuid (COUNT transaction external UUID).',
|
|
1157
1093
|
method: 'POST',
|
|
1158
1094
|
pathTemplate: '/partners/expense-receipts/{id}/match-manually',
|
|
1159
|
-
inputSchema: idBodyInputSchema,
|
|
1160
1095
|
requiresUserAuth: true,
|
|
1161
1096
|
readOnly: false,
|
|
1162
1097
|
destructive: false,
|
|
@@ -1167,7 +1102,6 @@ const tools = [
|
|
|
1167
1102
|
description: 'Unmatch an expense receipt from its linked transaction.',
|
|
1168
1103
|
method: 'DELETE',
|
|
1169
1104
|
pathTemplate: '/partners/expense-receipts/{id}/unmatch',
|
|
1170
|
-
inputSchema: idInputSchema,
|
|
1171
1105
|
requiresUserAuth: true,
|
|
1172
1106
|
readOnly: false,
|
|
1173
1107
|
destructive: true,
|
|
@@ -1178,7 +1112,6 @@ const tools = [
|
|
|
1178
1112
|
description: 'Generate a trial balance for the authenticated workspace. Put filters under `query`: `endDate` (required, YYYY-MM-DD — the as-of date), `startDate` (optional, defaults to fiscal-year start), `currency` (defaults to workspace currency), `transactionStatus` ("all" | "reviewed" | "unreviewed" | "reconciled" | "unreconciled"), `accounts` or `accountUuids` (comma-separated account UUIDs from `list_accounts` — do NOT pass internal numeric ids), `tags` or `tagUuids` (comma-separated tag UUIDs from `list_tags`), `noTags: "true"` (only entries with no tags), `accountType` (one of "Assets", "Liabilities", "Equity", "Income", "Expenses"). This MCP tool is read-only; no `body` is accepted.',
|
|
1179
1113
|
method: 'POST',
|
|
1180
1114
|
pathTemplate: '/partners/reports/trial-balance',
|
|
1181
|
-
inputSchema: queryInputSchema,
|
|
1182
1115
|
requiresUserAuth: true,
|
|
1183
1116
|
readOnly: true,
|
|
1184
1117
|
destructive: false,
|
|
@@ -1189,7 +1122,6 @@ const tools = [
|
|
|
1189
1122
|
description: 'Generate a P&L (income statement) for the authenticated workspace. Put filters under `query`: required `startDate` and `endDate` (YYYY-MM-DD); optional `currency`, `transactionStatus` ("all" | "reviewed" | "unreviewed" | "reconciled" | "unreconciled"), `categoryAccount`, `categoryAccountUuid`, or `categoryAccountUuids` (comma-separated account UUIDs from `list_accounts` — use this to filter to one or more income/expense categories such as "Freight & Courier"; do NOT pass internal numeric ids), `tags` or `tagUuids`, `customers` or `customerUuids`, `vendors` or `vendorUuids`, `projects` or `projectUuids`, `products` or `productUuids`, `isPnLByTag: true` (column-per-tag breakdown), `includeNoTag: true`, `reportYear` ("financial" | "calendar"). This MCP tool is read-only; no `body` is accepted. **Sign convention**: revenue rows are returned as positive amounts and expense rows as negative; net profit is the algebraic sum.',
|
|
1190
1123
|
method: 'POST',
|
|
1191
1124
|
pathTemplate: '/partners/reports/pnl',
|
|
1192
|
-
inputSchema: queryInputSchema,
|
|
1193
1125
|
requiresUserAuth: true,
|
|
1194
1126
|
readOnly: true,
|
|
1195
1127
|
destructive: false,
|
|
@@ -1200,7 +1132,6 @@ const tools = [
|
|
|
1200
1132
|
description: 'Generate a balance sheet for the authenticated workspace. Put filters under `query`: required `endDate` (YYYY-MM-DD — the as-of date); optional `startDate` (used as the prior-period comparison anchor), `currency`, `transactionStatus`, `accounts` or `accountUuids` (comma-separated account UUIDs from `list_accounts` — do NOT pass internal numeric ids), `tags` or `tagUuids`. This MCP tool is read-only; no `body` is accepted. Returns Assets / Liabilities / Equity sections with subtotals; the report fails to balance only when there are unposted manual entries — those are surfaced in the response payload.',
|
|
1201
1133
|
method: 'POST',
|
|
1202
1134
|
pathTemplate: '/partners/reports/balance-sheet',
|
|
1203
|
-
inputSchema: queryInputSchema,
|
|
1204
1135
|
requiresUserAuth: true,
|
|
1205
1136
|
readOnly: true,
|
|
1206
1137
|
destructive: false,
|
|
@@ -1212,7 +1143,6 @@ const tools = [
|
|
|
1212
1143
|
description: 'List P&L budgets for the authenticated workspace. Optional `query.status`: `draft`, `published`, or `archived`. Each budget returns its external UUID as `id`, metadata (name, startPeriod, cadence, actualPeriods, budgetPeriods, currencyCode, status, isOverall), and version summaries (versionNumber, label, isPublished).',
|
|
1213
1144
|
method: 'GET',
|
|
1214
1145
|
pathTemplate: '/partners/budgets',
|
|
1215
|
-
inputSchema: queryInputSchema,
|
|
1216
1146
|
requiresUserAuth: true,
|
|
1217
1147
|
readOnly: true,
|
|
1218
1148
|
destructive: false,
|
|
@@ -1223,7 +1153,6 @@ const tools = [
|
|
|
1223
1153
|
description: 'Get the workspace Overall Budget (if configured). Returns the same budget object shape as `list_budgets` rows, or null when no overall budget exists.',
|
|
1224
1154
|
method: 'GET',
|
|
1225
1155
|
pathTemplate: '/partners/budgets/overall',
|
|
1226
|
-
inputSchema: queryInputSchema,
|
|
1227
1156
|
requiresUserAuth: true,
|
|
1228
1157
|
readOnly: true,
|
|
1229
1158
|
destructive: false,
|
|
@@ -1234,7 +1163,6 @@ const tools = [
|
|
|
1234
1163
|
description: 'Create a draft budget and seed P&L budget lines for every active Income/Expenses account. Required body: `name`, `startPeriod` (YYYY-MM-DD), `cadence` (`monthly` | `yearly`), `actualPeriods` (>= 0), `budgetPeriods` (>= 1). Optional: `currencyCode` (defaults to workspace currency), `isOverall` (boolean — only one overall budget per workspace). Returns `{ budget, version }` with the initial versionNumber (usually 1). After create, import amounts with `bulk_update_budget_cells`.',
|
|
1235
1164
|
method: 'POST',
|
|
1236
1165
|
pathTemplate: '/partners/budgets',
|
|
1237
|
-
inputSchema: bodyInputSchema,
|
|
1238
1166
|
requiresUserAuth: true,
|
|
1239
1167
|
readOnly: false,
|
|
1240
1168
|
destructive: false,
|
|
@@ -1245,7 +1173,6 @@ const tools = [
|
|
|
1245
1173
|
description: 'Get a single budget by external UUID, including version summaries.',
|
|
1246
1174
|
method: 'GET',
|
|
1247
1175
|
pathTemplate: '/partners/budgets/{id}',
|
|
1248
|
-
inputSchema: idInputSchema,
|
|
1249
1176
|
requiresUserAuth: true,
|
|
1250
1177
|
readOnly: true,
|
|
1251
1178
|
destructive: false,
|
|
@@ -1256,7 +1183,6 @@ const tools = [
|
|
|
1256
1183
|
description: 'Update draft budget metadata by external UUID. Pass only fields to change: `name`, `startPeriod`, `cadence`, `actualPeriods`, `budgetPeriods`, `isOverall`. Rejected when the budget is published or locked.',
|
|
1257
1184
|
method: 'PATCH',
|
|
1258
1185
|
pathTemplate: '/partners/budgets/{id}',
|
|
1259
|
-
inputSchema: idBodyInputSchema,
|
|
1260
1186
|
requiresUserAuth: true,
|
|
1261
1187
|
readOnly: false,
|
|
1262
1188
|
destructive: false,
|
|
@@ -1267,7 +1193,6 @@ const tools = [
|
|
|
1267
1193
|
description: 'Export a budget grid for Excel round-trips. Returns `columns` (actual + budget period labels) and `rows` with `accountUuid`, `accountName`, `accountPath`, and per-period `values`. Optional `query.versionNumber` (defaults to latest version), `query.reportType` (`accrual` | `cash`), and `query.includeActuals` (`false` skips journal-entry actuals for faster budget-only export). Use `list_accounts` / `resolve_references` to map account names before re-importing edited rows.',
|
|
1268
1194
|
method: 'GET',
|
|
1269
1195
|
pathTemplate: '/partners/budgets/{id}/grid',
|
|
1270
|
-
inputSchema: idInputSchema,
|
|
1271
1196
|
requiresUserAuth: true,
|
|
1272
1197
|
readOnly: true,
|
|
1273
1198
|
destructive: false,
|
|
@@ -1278,7 +1203,6 @@ const tools = [
|
|
|
1278
1203
|
description: 'List version summaries for a budget: `versionNumber`, `label`, `isPublished`, `createdAt`. Use `versionNumber` on cell update tools.',
|
|
1279
1204
|
method: 'GET',
|
|
1280
1205
|
pathTemplate: '/partners/budgets/{id}/versions',
|
|
1281
|
-
inputSchema: idInputSchema,
|
|
1282
1206
|
requiresUserAuth: true,
|
|
1283
1207
|
readOnly: true,
|
|
1284
1208
|
destructive: false,
|
|
@@ -1289,7 +1213,6 @@ const tools = [
|
|
|
1289
1213
|
description: 'Atomically update up to 100 budget cell amounts on a **draft** version. Requires `id` (budget UUID) and `versionNumber`. Body: `{ updates: [{ accountUuid, periodStart (YYYY-MM-DD), amount }] }`. Each row must reference a P&L account UUID from `list_accounts` and a budget column periodStart from `get_budget_grid`. All rows succeed or fail together.',
|
|
1290
1214
|
method: 'PATCH',
|
|
1291
1215
|
pathTemplate: '/partners/budgets/{id}/versions/{versionNumber}/cells',
|
|
1292
|
-
inputSchema: idVersionNumberBodyInputSchema,
|
|
1293
1216
|
requiresUserAuth: true,
|
|
1294
1217
|
readOnly: false,
|
|
1295
1218
|
destructive: false,
|
|
@@ -1300,7 +1223,6 @@ const tools = [
|
|
|
1300
1223
|
description: 'Import budget amounts with partial-success semantics (recommended for spreadsheet imports). Same row shape as `update_budget_cells`: `{ updates: [{ accountUuid, periodStart, amount }, ...] }`. **Cap**: 100 rows per call; **recommended batch size**: ~25. Response: `{ successCount, errorCount, results: [{ index, success, budgetCellUpdate? | error }] }`. HTTP status is `201` when the batch is accepted even if some rows fail — retry only failed indices.',
|
|
1301
1224
|
method: 'POST',
|
|
1302
1225
|
pathTemplate: '/partners/budgets/{id}/versions/{versionNumber}/cells/bulk',
|
|
1303
|
-
inputSchema: idVersionNumberBodyInputSchema,
|
|
1304
1226
|
requiresUserAuth: true,
|
|
1305
1227
|
readOnly: false,
|
|
1306
1228
|
destructive: false,
|
|
@@ -1311,7 +1233,6 @@ const tools = [
|
|
|
1311
1233
|
description: 'Create a new draft budget version (copies lines and cell values from the previous version). Optional body: `label`. Returns the new version with an incremented `versionNumber`.',
|
|
1312
1234
|
method: 'POST',
|
|
1313
1235
|
pathTemplate: '/partners/budgets/{id}/versions',
|
|
1314
|
-
inputSchema: idOptionalBodyInputSchema,
|
|
1315
1236
|
requiresUserAuth: true,
|
|
1316
1237
|
readOnly: false,
|
|
1317
1238
|
destructive: false,
|
|
@@ -1322,7 +1243,6 @@ const tools = [
|
|
|
1322
1243
|
description: 'Publish a budget version and set budget status to `published`. Optional body: `versionNumber` (defaults to latest draft). Rejects cell edits on published versions.',
|
|
1323
1244
|
method: 'POST',
|
|
1324
1245
|
pathTemplate: '/partners/budgets/{id}/publish',
|
|
1325
|
-
inputSchema: idOptionalBodyInputSchema,
|
|
1326
1246
|
requiresUserAuth: true,
|
|
1327
1247
|
readOnly: false,
|
|
1328
1248
|
destructive: false,
|
|
@@ -1333,7 +1253,6 @@ const tools = [
|
|
|
1333
1253
|
description: 'Archive a budget by external UUID. Cannot archive the Overall Budget.',
|
|
1334
1254
|
method: 'POST',
|
|
1335
1255
|
pathTemplate: '/partners/budgets/{id}/archive',
|
|
1336
|
-
inputSchema: idOptionalBodyInputSchema,
|
|
1337
1256
|
requiresUserAuth: true,
|
|
1338
1257
|
readOnly: false,
|
|
1339
1258
|
destructive: true,
|
|
@@ -1344,7 +1263,6 @@ const tools = [
|
|
|
1344
1263
|
description: 'Duplicate a budget into a new draft. Required body: `newName`. Optional: `carryValues` (copy cell amounts), `isOverall`, `versionNumber` (source version; defaults to latest).',
|
|
1345
1264
|
method: 'POST',
|
|
1346
1265
|
pathTemplate: '/partners/budgets/{id}/duplicate',
|
|
1347
|
-
inputSchema: idBodyInputSchema,
|
|
1348
1266
|
requiresUserAuth: true,
|
|
1349
1267
|
readOnly: false,
|
|
1350
1268
|
destructive: false,
|
|
@@ -1365,12 +1283,65 @@ const tools = [
|
|
|
1365
1283
|
'Optional `query.include` is a comma-separated list of blocks to compute (omit any block you do not need): `workspace,cash,profitability,receivables,payables,taxObligations,connections`. Omitting `include` returns every block. This is the cheapest single call to populate an end-of-period dashboard or a "how is the business doing right now" summary.',
|
|
1366
1284
|
method: 'GET',
|
|
1367
1285
|
pathTemplate: '/partners/workspace-stats',
|
|
1368
|
-
inputSchema: queryInputSchema,
|
|
1369
1286
|
requiresUserAuth: true,
|
|
1370
1287
|
readOnly: true,
|
|
1371
1288
|
destructive: false,
|
|
1372
1289
|
},
|
|
1290
|
+
{
|
|
1291
|
+
name: 'COUNT_update_workspace',
|
|
1292
|
+
title: 'Update Workspace',
|
|
1293
|
+
description: 'Update workspace-level settings for the authenticated workspace. Currently supports `cutoverDate` (required, YYYY-MM-DD) — the date COUNT-managed bookkeeping begins; everything on/before it is summarized by opening balances rather than tracked line-by-line. Moving it backward (earlier) is always allowed. Moving it forward (later) is only allowed when the workspace has zero posted journal entries yet — this is a re-baseline guard, not a UI limitation, so it rejects with a 400 explaining the entry count if the workspace already has posted activity. Setting the cutover date for the first time is rejected with a 400 if the workspace already has an imported trial balance, since that would leave opening balances anchored to no cutover date — contact support to resolve first. Use `get_workspace_stats` (`workspace.cutoverDate`) to read the current value first.',
|
|
1294
|
+
method: 'PATCH',
|
|
1295
|
+
pathTemplate: '/partners/workspace',
|
|
1296
|
+
requiresUserAuth: true,
|
|
1297
|
+
readOnly: false,
|
|
1298
|
+
destructive: false,
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
name: 'COUNT_get_opening_balance',
|
|
1302
|
+
title: 'Get Opening Balance',
|
|
1303
|
+
description: 'Read the workspace\'s opening balance (COUNT calls this the "conversion balance" internally): status (`none`/`draft`/`published`), the cutover date it is anchored to, and the current rows (`accountUuid`, `accountName`, `accountType`, `debit`, `credit`). Call this before `COUNT_set_opening_balance` to check whether one already exists and needs `replaceExisting: true`.',
|
|
1304
|
+
method: 'GET',
|
|
1305
|
+
pathTemplate: '/partners/opening-balance',
|
|
1306
|
+
requiresUserAuth: true,
|
|
1307
|
+
readOnly: true,
|
|
1308
|
+
destructive: false,
|
|
1309
|
+
},
|
|
1310
|
+
{
|
|
1311
|
+
name: 'COUNT_set_opening_balance',
|
|
1312
|
+
title: 'Set Opening Balance',
|
|
1313
|
+
description: 'Set the workspace\'s opening balance as of its cutover date (use `COUNT_update_workspace` to set the cutover date first). Body: `rows` (required, non-empty array of `{ accountUuid, debit, credit }` — total debits must equal total credits) and `replaceExisting` (required `true` to overwrite an existing draft or published opening balance; omitted/false rejects with 409 if one already exists — check first with `COUNT_get_opening_balance`). This drafts and immediately publishes in one call: it posts the balancing journal entry at the cutover date, so it only works while the workspace is still onboarding (`team.isOnboarding === true`) and rejects with 400 once onboarding is complete. If publish-time validation fails (e.g. unbalanced control accounts) after the draft was saved, the draft persists — retry with `replaceExisting: true` after fixing the rows.',
|
|
1314
|
+
method: 'POST',
|
|
1315
|
+
pathTemplate: '/partners/opening-balance',
|
|
1316
|
+
requiresUserAuth: true,
|
|
1317
|
+
readOnly: false,
|
|
1318
|
+
destructive: false,
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
name: 'COUNT_create_reconciliation',
|
|
1322
|
+
title: 'Create Reconciliation',
|
|
1323
|
+
description: 'Start a bank reconciliation for an account: creates a DRAFT reconciliation record for a statement period. Body: `accountUuid` (required, from `list_accounts`), `endingBalanceDate` (required, YYYY-MM-DD — the statement ending date), `endingBalanceAmount` (required — the statement ending balance). Rejects with 400 if a draft or completed reconciliation already exists for that date, or if a later completed reconciliation already exists for this account (reconciliations must complete in date order). The opening balance is taken automatically from the account\'s last completed reconciliation. The response `id` is the reconciliation UUID — pass it to `COUNT_complete_reconciliation` to lock it once the ending balance is verified. Only reconciles journal entries already marked reviewed unless `COUNT_complete_reconciliation` is called with `autoReconcile: true`.',
|
|
1324
|
+
method: 'POST',
|
|
1325
|
+
pathTemplate: '/partners/reconciliations',
|
|
1326
|
+
requiresUserAuth: true,
|
|
1327
|
+
readOnly: false,
|
|
1328
|
+
destructive: false,
|
|
1329
|
+
},
|
|
1330
|
+
{
|
|
1331
|
+
name: 'COUNT_complete_reconciliation',
|
|
1332
|
+
title: 'Complete Reconciliation',
|
|
1333
|
+
description: 'Lock a draft reconciliation by its UUID (from `COUNT_create_reconciliation`), marking every reviewed journal entry in the account for that period as `reconciled: true` and stamping them with this reconciliation. Optional `body.autoReconcile: true` also marks unreviewed entries in the period as reviewed and reconciles them (defaults to false — reconciling only what a human already reviewed). Rejects with 404 if the reconciliation is not a pending draft (already completed, or does not exist), and with 400 if the ending balance date falls in a book-closed sealed period, or if completing it would violate reconciliation date ordering (an earlier draft is still open, or a later reconciliation is already complete). This is the only way to set `reconciled: true` on transactions/journal entries via the partner API — there is no direct writable field for it.',
|
|
1334
|
+
method: 'PATCH',
|
|
1335
|
+
pathTemplate: '/partners/reconciliations/{id}/complete',
|
|
1336
|
+
requiresUserAuth: true,
|
|
1337
|
+
readOnly: false,
|
|
1338
|
+
destructive: false,
|
|
1339
|
+
},
|
|
1373
1340
|
];
|
|
1341
|
+
const tools = rawTools.map((_tool) => ({
|
|
1342
|
+
..._tool,
|
|
1343
|
+
inputSchema: toolInputSchemas.getToolInputSchema({ toolName: _tool.name }),
|
|
1344
|
+
}));
|
|
1374
1345
|
export const toolDefinitions = tools;
|
|
1375
1346
|
export function getToolDefinition(params) {
|
|
1376
1347
|
const { toolName } = params;
|