Update Category Budget
ynab_update_category_budgetUpdate a category's budgeted amount for a specific month to allocate funds or move money between categories. This sets the total budgeted amount, not an increment.
Instructions
Updates the budgeted amount for a category in a specific month. Use this to allocate funds to categories or move money between categories.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| budgetId | No | The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable) | |
| month | Yes | The budget month in ISO format (e.g. 2024-01-01). Must be the first day of the month. | |
| categoryId | Yes | The ID of the category to update | |
| budgeted | Yes | The amount to budget in dollars (e.g. 500.00). This sets the total budgeted amount, not an increment. |
Implementation Reference
- The main `execute` function that performs the YNAB API call to update a category's budget for a specific month. It converts dollars to milliunits, calls `api.categories.updateMonthCategory`, and returns a formatted response.
export async function execute(input: UpdateCategoryBudgetInput, api: ynab.API) { try { const budgetId = getBudgetId(input.budgetId); const budgetedMilliunits = Math.round(input.budgeted * 1000); const response = await api.categories.updateMonthCategory( budgetId, input.month, input.categoryId, { category: { budgeted: budgetedMilliunits, }, } ); if (!response.data.category) { throw new Error("Failed to update category - no category data returned"); } const category = response.data.category; return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, category: { id: category.id, name: category.name, budgeted: (category.budgeted / 1000).toFixed(2), activity: (category.activity / 1000).toFixed(2), balance: (category.balance / 1000).toFixed(2), }, message: `Successfully updated ${category.name} budget to $${(category.budgeted / 1000).toFixed(2)}`, }, null, 2), }], }; } catch (error) { console.error("Error updating category budget:", error); return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: getErrorMessage(error), }, null, 2), }], }; } } - The tool name, description, and Zod-based input schema defining the expected parameters: budgetId (optional), month (ISO date), categoryId, and budgeted (dollar amount).
export const name = "ynab_update_category_budget"; export const description = "Updates the budgeted amount for a category in a specific month. Use this to allocate funds to categories or move money between categories."; export const inputSchema = { budgetId: z.string().optional().describe("The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"), month: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("The budget month in ISO format (e.g. 2024-01-01). Must be the first day of the month."), categoryId: z.string().describe("The ID of the category to update"), budgeted: z.number().describe("The amount to budget in dollars (e.g. 500.00). This sets the total budgeted amount, not an increment."), }; - Import of `z` from the zod library used to define the input schema.
import { z } from "zod"; - Helper function `getBudgetId` that resolves the budget ID from input or falls back to the YNAB_BUDGET_ID environment variable.
function getBudgetId(inputBudgetId?: string): string { const budgetId = inputBudgetId || process.env.YNAB_BUDGET_ID || ""; if (!budgetId) { throw new Error("No budget ID provided. Please provide a budget ID or set the YNAB_BUDGET_ID environment variable."); } return budgetId; } - src/tools/errorUtils.ts:5-39 (helper)Utility function `getErrorMessage` used to extract a meaningful error message from various error types including YNAB API error responses.
export function getErrorMessage(error: unknown): string { // Handle standard Error objects if (error instanceof Error) { return error.message; } // Handle YNAB API error responses which have the structure: // { error: { id: '...', name: '...', detail: '...' } } if ( typeof error === 'object' && error !== null && 'error' in error && typeof (error as any).error === 'object' ) { const ynabError = (error as any).error; if (ynabError.detail) { return ynabError.detail; } if (ynabError.name) { return ynabError.name; } } // Fallback: try to stringify the error try { const stringified = JSON.stringify(error); if (stringified !== '{}') { return stringified; } } catch { // Ignore stringify errors } return 'Unknown error occurred'; }