update_transactions_bulk
Batch update 1 to 500 transactions by providing their IDs and at least one writable field. Cannot modify split or grouped transactions.
Instructions
Update multiple transactions in a single call (1-500). Each entry must include id plus at least one writable field. Cannot be used to modify split or grouped transactions.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| transactions | Yes | Array of partial transaction updates, each keyed by its `id`. |
Implementation Reference
- src/tools/transactions.ts:453-497 (registration)Registration of the 'update_transactions_bulk' tool with MCP server, including description, input schema, and handler.
server.registerTool( "update_transactions_bulk", { description: "Update multiple transactions in a single call (1-500). Each entry must include `id` plus at least one writable field. Cannot be used to modify split or grouped transactions.", inputSchema: { transactions: z .array( updateTransactionFieldsSchema.extend({ id: z.coerce .number() .describe( "ID of the transaction to update (required).", ), }), ) .min(1) .max(500) .describe( "Array of partial transaction updates, each keyed by its `id`.", ), }, annotations: { idempotentHint: true, }, }, async ({ transactions }) => { try { const response = await api.put("/transactions", { transactions, }); if (!response.ok) { return handleApiError( response, "Failed to bulk update transactions", ); } return dataResponse(await response.json()); } catch (error) { return catchError(error, "Failed to bulk update transactions"); } }, ); - src/tools/transactions.ts:479-496 (handler)Handler function that calls api.put('/transactions', {transactions}) and returns the response.
async ({ transactions }) => { try { const response = await api.put("/transactions", { transactions, }); if (!response.ok) { return handleApiError( response, "Failed to bulk update transactions", ); } return dataResponse(await response.json()); } catch (error) { return catchError(error, "Failed to bulk update transactions"); } }, - src/tools/transactions.ts:458-474 (schema)Input schema: array of 1-500 transaction objects, each extending updateTransactionFieldsSchema with a required 'id' field.
inputSchema: { transactions: z .array( updateTransactionFieldsSchema.extend({ id: z.coerce .number() .describe( "ID of the transaction to update (required).", ), }), ) .min(1) .max(500) .describe( "Array of partial transaction updates, each keyed by its `id`.", ), }, - src/tools/transactions.ts:103-128 (schema)updateTransactionFieldsSchema defines writable fields for updating a transaction.
const updateTransactionFieldsSchema = z.object({ date: dateString.optional(), amount: z.coerce.number().optional(), currency: z.string().length(3).optional(), payee: z.string().max(140).optional(), category_id: z.coerce.number().nullable().optional(), notes: z.string().max(350).nullable().optional(), manual_account_id: z.coerce.number().nullable().optional(), plaid_account_id: z.coerce.number().nullable().optional(), recurring_id: z.coerce.number().nullable().optional(), status: writeStatusEnum.optional(), tag_ids: z .array(z.coerce.number()) .optional() .describe( "Replaces all existing tags on the transaction. Mutually exclusive with additional_tag_ids.", ), additional_tag_ids: z .array(z.coerce.number()) .optional() .describe( "Adds these tags to the existing transaction tags. Mutually exclusive with tag_ids.", ), external_id: z.string().max(75).nullable().optional(), custom_metadata: z.record(z.unknown()).nullable().optional(), }); - src/api.ts:146-153 (helper)API client helpers: api.put() used by the handler to make the PUT /transactions request.
export const api = { get: (path: string) => apiRequest("GET", path), post: (path: string, body?: unknown) => apiRequest("POST", path, body), put: (path: string, body: unknown) => apiRequest("PUT", path, body), delete: (path: string, body?: unknown) => apiRequest("DELETE", path, body), upload: (path: string, formData: FormData) => apiUpload("POST", path, formData), };