{"openapi":"3.1.0","info":{"title":"Tally Budget API","version":"1.0.0","description":"Public API for Tally — a budgeting app. Supports API key (`tb_live_` / `tb_test_`) and Supabase session JWT in `Authorization: Bearer`. Human-readable guides live at `/docs` on the marketing site."},"servers":[{"url":"/api","description":"Default"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key (tb_live_... or tb_test_...) or Supabase session JWT token"}},"schemas":{"UserProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"created_at":{"type":"string"},"subscription_status":{"type":"string"},"features":{"type":"object","properties":{"is_pro":{"type":"boolean"}},"required":["is_pro"]}},"required":["id","email","created_at","subscription_status","features"]},"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"}},"required":["type","code","message","request_id"]}},"required":["error"]},"Subscription":{"type":"object","properties":{"is_pro":{"type":"boolean"},"status":{"type":"string","enum":["active","trialing","past_due","canceled","expired","none"]},"source":{"type":["string","null"],"enum":["app_store","play_store","stripe","entitlement","none",null]},"plan":{"type":["string","null"]},"expires_at":{"type":["string","null"]}},"required":["is_pro","status","source","plan","expires_at"]},"Budget":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"start_date":{"type":"string"},"end_date":{"type":"string"},"total_income":{"type":"number"},"total_spend":{"type":"number"},"household_id":{"type":["string","null"],"format":"uuid"},"created_at":{"type":"string"}},"required":["id","name","start_date","end_date","total_income","total_spend","household_id","created_at"]},"Pagination":{"type":"object","properties":{"next_cursor":{"type":["string","null"]},"has_more":{"type":"boolean"}},"required":["next_cursor","has_more"]},"Category":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":"string"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string"},"allocation_value":{"type":"number"},"total_spend":{"type":"number"},"sort_order":{"type":"number"}},"required":["id","name","color","icon","allocation_type","allocation_value","total_spend","sort_order"]},"Transaction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"budget_id":{"type":"string","format":"uuid"},"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number"},"date":{"type":"string"},"details":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","budget_id","category_id","subcategory_id","amount","date","details","created_at"]},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"environment":{"type":"string","enum":["live","test"]},"last_used_at":{"type":["string","null"]},"expires_at":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","name","prefix","scopes","environment","last_used_at","expires_at","created_at"]},"ApiKeyCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string"},"secret":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"environment":{"type":"string","enum":["live","test"]},"expires_at":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","name","prefix","secret","scopes","environment","expires_at","created_at"]}},"parameters":{}},"paths":{"/v1/me":{"get":{"summary":"Get current user profile","description":"Returns the authenticated user's profile, email, creation time, subscription status string, and feature flags (e.g. `is_pro`).","tags":["User"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"User profile","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/UserProfile"}},"required":["data"]}}}},"401":{"description":"Authentication error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/subscriptions/me":{"get":{"summary":"Get current subscription status","description":"Returns normalized subscription state: Pro flag, status, billing source (App Store, Play, Stripe, etc.), plan name, and renewal/expiry when available.","tags":["Subscription"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Subscription status","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Subscription"}},"required":["data"]}}}}}}},"/v1/budgets":{"get":{"summary":"List budgets","description":"Cursor-paginated list. Filter by `household_id` or `status` (`active` / `archived`). Use `next_cursor` from `pagination` when `has_more` is true.","tags":["Budgets"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"household_id","in":"query"},{"schema":{"type":"string","enum":["active","archived"]},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"List of budgets","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Budget"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]}}}}}},"post":{"summary":"Create a budget","description":"Creates a budget with a date range. `total_income` defaults if omitted per server rules. `household_id` may be null for personal budgets.","tags":["Budgets"],"security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"start_date":{"type":"string"},"end_date":{"type":"string"},"total_income":{"type":"number"},"household_id":{"type":["string","null"],"format":"uuid"}},"required":["name","start_date","end_date"]}}}},"responses":{"201":{"description":"Created budget","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Budget"}},"required":["data"]}}}}}}},"/v1/budgets/{budgetId}":{"get":{"summary":"Get a budget","description":"Fetches a single budget by UUID. Returns `404` if the budget does not exist or is not accessible.","tags":["Budgets"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"budgetId","in":"path"}],"responses":{"200":{"description":"Budget details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Budget"}},"required":["data"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"summary":"Update a budget","description":"Partial update: include only fields to change (`name`, `start_date`, `end_date`, `total_income`).","tags":["Budgets"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"budgetId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"start_date":{"type":"string"},"end_date":{"type":"string"},"total_income":{"type":"number"}}}}}},"responses":{"200":{"description":"Updated budget","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Budget"}},"required":["data"]}}}}}},"delete":{"summary":"Delete a budget","description":"Permanently removes the budget. Related data behavior depends on server cascade rules.","tags":["Budgets"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"budgetId","in":"path"}],"responses":{"200":{"description":"Budget deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"]}},"required":["data"]}}}}}}},"/v1/budgets/{budgetId}/categories":{"get":{"summary":"List categories for a budget","description":"Returns all categories for the budget, including allocation type/value and spend rollups.","tags":["Budgets","Categories"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"budgetId","in":"path"}],"responses":{"200":{"description":"List of categories","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}}},"required":["data"]}}}}}},"post":{"summary":"Create a category in a budget","description":"`allocation_type` is `fixed` (currency amount) or `percentage` of income. Optional `sort_order` controls display order.","tags":["Budgets","Categories"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"budgetId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"color":{"type":"string"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number"},"sort_order":{"type":"number"}},"required":["name","allocation_type","allocation_value"]}}}},"responses":{"201":{"description":"Created category","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Category"}},"required":["data"]}}}}}}},"/v1/transactions":{"get":{"summary":"List transactions","description":"Filter by `budget_id`, category/subcategory, optional `start_date` / `end_date`, optional `min_amount` / `max_amount`, and optional `details_search` (case-insensitive substring on details). Sort by `date`, `amount`, or `created_at` with `order` asc/desc.","tags":["Transactions"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"budget_id","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"category_id","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"subcategory_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"start_date","in":"query"},{"schema":{"type":"string"},"required":false,"name":"end_date","in":"query"},{"schema":{"type":"number"},"required":false,"name":"min_amount","in":"query"},{"schema":{"type":"number"},"required":false,"name":"max_amount","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200},"required":false,"name":"details_search","in":"query"},{"schema":{"type":"string","enum":["date","amount","created_at"]},"required":false,"name":"sort","in":"query"},{"schema":{"type":"string","enum":["asc","desc"]},"required":false,"name":"order","in":"query"}],"responses":{"200":{"description":"List of transactions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]}}}}}},"post":{"summary":"Create a transaction","description":"Creates a line item on a budget. `amount` sign convention matches your product rules (e.g. negative for spend). Category fields are optional.","tags":["Transactions"],"security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number"},"date":{"type":"string"},"details":{"type":["string","null"]}},"required":["budget_id","amount","date"]}}}},"responses":{"201":{"description":"Created transaction","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Transaction"}},"required":["data"]}}}}}}},"/v1/transactions/{transactionId}":{"get":{"summary":"Get a transaction","description":"Returns one transaction by ID if it belongs to an accessible budget.","tags":["Transactions"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"transactionId","in":"path"}],"responses":{"200":{"description":"Transaction details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Transaction"}},"required":["data"]}}}}}},"patch":{"summary":"Update a transaction","description":"Partial update of category, subcategory, amount, date, or details.","tags":["Transactions"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"transactionId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number"},"date":{"type":"string"},"details":{"type":["string","null"]}}}}}},"responses":{"200":{"description":"Updated transaction","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Transaction"}},"required":["data"]}}}}}},"delete":{"summary":"Delete a transaction","description":"Removes the transaction. Response includes `{ data: { deleted: true } }` on success.","tags":["Transactions"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"transactionId","in":"path"}],"responses":{"200":{"description":"Transaction deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"]}},"required":["data"]}}}}}}},"/v1/ai-agent/usage":{"get":{"summary":"Get AI usage and limits","description":"Returns rolling 4-hour and 7-day spend totals (USD), configured limits, remaining budget, max single-turn cost, and window start timestamps for the authenticated user.","tags":["AI agent"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Usage snapshot","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"tier":{"type":"string","enum":["free","pro"]},"limits":{"type":"object","properties":{"four_hour_cost_usd":{"type":"number"},"seven_day_cost_usd":{"type":"number"}},"required":["four_hour_cost_usd","seven_day_cost_usd"]},"usage":{"type":"object","properties":{"four_hour_usd":{"type":"number"},"seven_day_usd":{"type":"number"}},"required":["four_hour_usd","seven_day_usd"]},"remaining":{"type":"object","properties":{"four_hour_usd":{"type":"number"},"seven_day_usd":{"type":"number"}},"required":["four_hour_usd","seven_day_usd"]},"max_turn_cost_usd":{"type":"number"},"windows":{"type":"object","properties":{"four_hour_started_at":{"type":"string"},"seven_day_started_at":{"type":"string"}},"required":["four_hour_started_at","seven_day_started_at"]}},"required":["tier","limits","usage","remaining","max_turn_cost_usd","windows"]}},"required":["data"]}}}},"401":{"description":"Authentication error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/ai-agent/conversations":{"get":{"summary":"List AI conversations","description":"Returns the authenticated user's recent AI conversation summaries. Soft-deleted conversations are excluded. Use `offset` for pagination with `limit`.","tags":["AI agent"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"maximum":5000,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"conversations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":["string","null"]},"metadata":{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"system_prompt_cache":{"type":"object","properties":{"rules_version":{"type":"string"},"budget_focus_id":{"type":["string","null"],"format":"uuid"},"user_display_name":{"type":"string"},"prompt":{"type":"string"},"built_at":{"type":"string"}},"required":["rules_version","budget_focus_id","prompt","built_at"]}}},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_message_at":{"type":"string"}},"required":["id","title","metadata","created_at","updated_at","last_message_at"]}}},"required":["conversations"]}},"required":["data"]}}}}}},"post":{"summary":"Create an AI conversation","description":"Creates a new persisted AI conversation for the authenticated user. The conversation can then be used by both web and mobile clients.","tags":["AI agent"],"security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":160},"metadata":{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"system_prompt_cache":{"type":"object","properties":{"rules_version":{"type":"string"},"budget_focus_id":{"type":["string","null"],"format":"uuid"},"user_display_name":{"type":"string"},"prompt":{"type":"string"},"built_at":{"type":"string"}},"required":["rules_version","budget_focus_id","prompt","built_at"]}}}}}}}},"responses":{"201":{"description":"Created conversation thread","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"conversation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":["string","null"]},"metadata":{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"system_prompt_cache":{"type":"object","properties":{"rules_version":{"type":"string"},"budget_focus_id":{"type":["string","null"],"format":"uuid"},"user_display_name":{"type":"string"},"prompt":{"type":"string"},"built_at":{"type":"string"}},"required":["rules_version","budget_focus_id","prompt","built_at"]}}},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_message_at":{"type":"string"}},"required":["id","title","metadata","created_at","updated_at","last_message_at"]},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string"},"parts":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["reasoning"]},"text":{"type":"string","minLength":1,"maxLength":100000}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"text":{"type":"string","minLength":1}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["tool_result"]},"tool_name":{"type":"string","enum":["listBudgets","listCategories","findTransactions","getTransaction","analyzeSpending","draftCreateBudget","draftUpdateBudget","draftCreateCategory","draftUpdateCategory","draftCreateTransaction","draftUpdateTransaction"]},"title":{"type":"string"},"input":{"type":"object","additionalProperties":{}},"output":{}},"required":["type","tool_name"]},{"type":"object","properties":{"type":{"type":"string","enum":["pending_action"]},"pending_action":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"message_id":{"type":["string","null"],"format":"uuid"},"action_type":{"type":"string","enum":["create_budget","update_budget","create_category","update_category","create_transaction","update_transaction"]},"action":{"oneOf":[{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0,"default":0},"household_id":{"type":["string","null"],"format":"uuid"},"type":{"type":"string","enum":["create_budget"]}},"required":["name","start_date","end_date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_budget"]},"budget_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0}}}},"required":["type","budget_id","changes"]},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","default":"#3B82F6"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer","default":0},"type":{"type":"string","enum":["create_category"]},"budget_id":{"type":"string","format":"uuid"}},"required":["name","allocation_type","allocation_value","type","budget_id"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_category"]},"category_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer"}}}},"required":["type","category_id","changes"]},{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000},"type":{"type":"string","enum":["create_transaction"]}},"required":["budget_id","amount","date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_transaction"]},"transaction_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000}}}},"required":["type","transaction_id","changes"]}]},"title":{"type":"string","minLength":1,"maxLength":160},"summary":{"type":"string","minLength":1,"maxLength":400},"confirmation_message":{"type":"string","minLength":1,"maxLength":400},"status":{"type":"string","enum":["pending","executed","cancelled","expired"]},"created_at":{"type":"string"},"resolved_at":{"type":["string","null"]},"executed_entity_type":{"type":["string","null"],"enum":["budget","category","transaction",null]},"executed_entity_id":{"type":["string","null"],"format":"uuid"}},"required":["id","conversation_id","message_id","action_type","action","title","summary","confirmation_message","status","created_at","resolved_at","executed_entity_type","executed_entity_id"]}},"required":["type","pending_action"]}]}},"created_at":{"type":"string"}},"required":["id","conversation_id","role","content","parts","created_at"]}},"pending_actions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"message_id":{"type":["string","null"],"format":"uuid"},"action_type":{"type":"string","enum":["create_budget","update_budget","create_category","update_category","create_transaction","update_transaction"]},"action":{"oneOf":[{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0,"default":0},"household_id":{"type":["string","null"],"format":"uuid"},"type":{"type":"string","enum":["create_budget"]}},"required":["name","start_date","end_date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_budget"]},"budget_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0}}}},"required":["type","budget_id","changes"]},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","default":"#3B82F6"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer","default":0},"type":{"type":"string","enum":["create_category"]},"budget_id":{"type":"string","format":"uuid"}},"required":["name","allocation_type","allocation_value","type","budget_id"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_category"]},"category_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer"}}}},"required":["type","category_id","changes"]},{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000},"type":{"type":"string","enum":["create_transaction"]}},"required":["budget_id","amount","date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_transaction"]},"transaction_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000}}}},"required":["type","transaction_id","changes"]}]},"title":{"type":"string","minLength":1,"maxLength":160},"summary":{"type":"string","minLength":1,"maxLength":400},"confirmation_message":{"type":"string","minLength":1,"maxLength":400},"status":{"type":"string","enum":["pending","executed","cancelled","expired"]},"created_at":{"type":"string"},"resolved_at":{"type":["string","null"]},"executed_entity_type":{"type":["string","null"],"enum":["budget","category","transaction",null]},"executed_entity_id":{"type":["string","null"],"format":"uuid"}},"required":["id","conversation_id","message_id","action_type","action","title","summary","confirmation_message","status","created_at","resolved_at","executed_entity_type","executed_entity_id"]}}},"required":["conversation","messages","pending_actions"]}},"required":["data"]}}}}}}},"/v1/ai-agent/conversations/{conversationId}":{"get":{"summary":"Get AI conversation thread","description":"Returns a persisted AI conversation, all visible messages, and any active pending actions for the authenticated user.","tags":["AI agent"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Conversation thread","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"conversation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":["string","null"]},"metadata":{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"system_prompt_cache":{"type":"object","properties":{"rules_version":{"type":"string"},"budget_focus_id":{"type":["string","null"],"format":"uuid"},"user_display_name":{"type":"string"},"prompt":{"type":"string"},"built_at":{"type":"string"}},"required":["rules_version","budget_focus_id","prompt","built_at"]}}},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_message_at":{"type":"string"}},"required":["id","title","metadata","created_at","updated_at","last_message_at"]},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string"},"parts":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["reasoning"]},"text":{"type":"string","minLength":1,"maxLength":100000}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"text":{"type":"string","minLength":1}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["tool_result"]},"tool_name":{"type":"string","enum":["listBudgets","listCategories","findTransactions","getTransaction","analyzeSpending","draftCreateBudget","draftUpdateBudget","draftCreateCategory","draftUpdateCategory","draftCreateTransaction","draftUpdateTransaction"]},"title":{"type":"string"},"input":{"type":"object","additionalProperties":{}},"output":{}},"required":["type","tool_name"]},{"type":"object","properties":{"type":{"type":"string","enum":["pending_action"]},"pending_action":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"message_id":{"type":["string","null"],"format":"uuid"},"action_type":{"type":"string","enum":["create_budget","update_budget","create_category","update_category","create_transaction","update_transaction"]},"action":{"oneOf":[{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0,"default":0},"household_id":{"type":["string","null"],"format":"uuid"},"type":{"type":"string","enum":["create_budget"]}},"required":["name","start_date","end_date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_budget"]},"budget_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0}}}},"required":["type","budget_id","changes"]},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","default":"#3B82F6"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer","default":0},"type":{"type":"string","enum":["create_category"]},"budget_id":{"type":"string","format":"uuid"}},"required":["name","allocation_type","allocation_value","type","budget_id"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_category"]},"category_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer"}}}},"required":["type","category_id","changes"]},{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000},"type":{"type":"string","enum":["create_transaction"]}},"required":["budget_id","amount","date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_transaction"]},"transaction_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000}}}},"required":["type","transaction_id","changes"]}]},"title":{"type":"string","minLength":1,"maxLength":160},"summary":{"type":"string","minLength":1,"maxLength":400},"confirmation_message":{"type":"string","minLength":1,"maxLength":400},"status":{"type":"string","enum":["pending","executed","cancelled","expired"]},"created_at":{"type":"string"},"resolved_at":{"type":["string","null"]},"executed_entity_type":{"type":["string","null"],"enum":["budget","category","transaction",null]},"executed_entity_id":{"type":["string","null"],"format":"uuid"}},"required":["id","conversation_id","message_id","action_type","action","title","summary","confirmation_message","status","created_at","resolved_at","executed_entity_type","executed_entity_id"]}},"required":["type","pending_action"]}]}},"created_at":{"type":"string"}},"required":["id","conversation_id","role","content","parts","created_at"]}},"pending_actions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"message_id":{"type":["string","null"],"format":"uuid"},"action_type":{"type":"string","enum":["create_budget","update_budget","create_category","update_category","create_transaction","update_transaction"]},"action":{"oneOf":[{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0,"default":0},"household_id":{"type":["string","null"],"format":"uuid"},"type":{"type":"string","enum":["create_budget"]}},"required":["name","start_date","end_date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_budget"]},"budget_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0}}}},"required":["type","budget_id","changes"]},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","default":"#3B82F6"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer","default":0},"type":{"type":"string","enum":["create_category"]},"budget_id":{"type":"string","format":"uuid"}},"required":["name","allocation_type","allocation_value","type","budget_id"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_category"]},"category_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer"}}}},"required":["type","category_id","changes"]},{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000},"type":{"type":"string","enum":["create_transaction"]}},"required":["budget_id","amount","date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_transaction"]},"transaction_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000}}}},"required":["type","transaction_id","changes"]}]},"title":{"type":"string","minLength":1,"maxLength":160},"summary":{"type":"string","minLength":1,"maxLength":400},"confirmation_message":{"type":"string","minLength":1,"maxLength":400},"status":{"type":"string","enum":["pending","executed","cancelled","expired"]},"created_at":{"type":"string"},"resolved_at":{"type":["string","null"]},"executed_entity_type":{"type":["string","null"],"enum":["budget","category","transaction",null]},"executed_entity_id":{"type":["string","null"],"format":"uuid"}},"required":["id","conversation_id","message_id","action_type","action","title","summary","confirmation_message","status","created_at","resolved_at","executed_entity_type","executed_entity_id"]}}},"required":["conversation","messages","pending_actions"]}},"required":["data"]}}}}}},"delete":{"summary":"Soft-delete an AI conversation","description":"Soft-deletes a conversation and makes its related messages and pending actions inactive without hard-deleting stored history.","tags":["AI agent"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Conversation soft-deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"]}},"required":["data"]}}}}}}},"/v1/ai-agent/conversations/{conversationId}/messages":{"post":{"summary":"Send a user turn to the AI conversation","description":"Appends a user message to the conversation and returns the updated thread after either resolving a pending action or generating the assistant's next response. By default the response is JSON. With `?stream=1` or `Accept: text/event-stream`, the server streams Server-Sent Events (same auth as JSON). SSE event names: `partial_output` (partial structured assistant output), `step` (AI SDK stream progress such as tool calls), `done` (payload `{ data: AiConversationThread }` matching the JSON shape), `error` (API error envelope).","tags":["AI agent"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","enum":["1"]},"required":false,"name":"stream","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1,"maxLength":8000},"pending_action_id":{"type":"string","format":"uuid"}},"required":["content"]}}}},"responses":{"200":{"description":"Updated conversation thread (JSON) or SSE stream","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"conversation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":["string","null"]},"metadata":{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"system_prompt_cache":{"type":"object","properties":{"rules_version":{"type":"string"},"budget_focus_id":{"type":["string","null"],"format":"uuid"},"user_display_name":{"type":"string"},"prompt":{"type":"string"},"built_at":{"type":"string"}},"required":["rules_version","budget_focus_id","prompt","built_at"]}}},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_message_at":{"type":"string"}},"required":["id","title","metadata","created_at","updated_at","last_message_at"]},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string"},"parts":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["reasoning"]},"text":{"type":"string","minLength":1,"maxLength":100000}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"text":{"type":"string","minLength":1}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["tool_result"]},"tool_name":{"type":"string","enum":["listBudgets","listCategories","findTransactions","getTransaction","analyzeSpending","draftCreateBudget","draftUpdateBudget","draftCreateCategory","draftUpdateCategory","draftCreateTransaction","draftUpdateTransaction"]},"title":{"type":"string"},"input":{"type":"object","additionalProperties":{}},"output":{}},"required":["type","tool_name"]},{"type":"object","properties":{"type":{"type":"string","enum":["pending_action"]},"pending_action":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"message_id":{"type":["string","null"],"format":"uuid"},"action_type":{"type":"string","enum":["create_budget","update_budget","create_category","update_category","create_transaction","update_transaction"]},"action":{"oneOf":[{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0,"default":0},"household_id":{"type":["string","null"],"format":"uuid"},"type":{"type":"string","enum":["create_budget"]}},"required":["name","start_date","end_date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_budget"]},"budget_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0}}}},"required":["type","budget_id","changes"]},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","default":"#3B82F6"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer","default":0},"type":{"type":"string","enum":["create_category"]},"budget_id":{"type":"string","format":"uuid"}},"required":["name","allocation_type","allocation_value","type","budget_id"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_category"]},"category_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer"}}}},"required":["type","category_id","changes"]},{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000},"type":{"type":"string","enum":["create_transaction"]}},"required":["budget_id","amount","date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_transaction"]},"transaction_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000}}}},"required":["type","transaction_id","changes"]}]},"title":{"type":"string","minLength":1,"maxLength":160},"summary":{"type":"string","minLength":1,"maxLength":400},"confirmation_message":{"type":"string","minLength":1,"maxLength":400},"status":{"type":"string","enum":["pending","executed","cancelled","expired"]},"created_at":{"type":"string"},"resolved_at":{"type":["string","null"]},"executed_entity_type":{"type":["string","null"],"enum":["budget","category","transaction",null]},"executed_entity_id":{"type":["string","null"],"format":"uuid"}},"required":["id","conversation_id","message_id","action_type","action","title","summary","confirmation_message","status","created_at","resolved_at","executed_entity_type","executed_entity_id"]}},"required":["type","pending_action"]}]}},"created_at":{"type":"string"}},"required":["id","conversation_id","role","content","parts","created_at"]}},"pending_actions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"message_id":{"type":["string","null"],"format":"uuid"},"action_type":{"type":"string","enum":["create_budget","update_budget","create_category","update_category","create_transaction","update_transaction"]},"action":{"oneOf":[{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0,"default":0},"household_id":{"type":["string","null"],"format":"uuid"},"type":{"type":"string","enum":["create_budget"]}},"required":["name","start_date","end_date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_budget"]},"budget_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_income":{"type":"number","minimum":0}}}},"required":["type","budget_id","changes"]},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","default":"#3B82F6"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer","default":0},"type":{"type":"string","enum":["create_category"]},"budget_id":{"type":"string","format":"uuid"}},"required":["name","allocation_type","allocation_value","type","budget_id"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_category"]},"category_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string"},"icon":{"type":["string","null"]},"allocation_type":{"type":"string","enum":["fixed","percentage"]},"allocation_value":{"type":"number","minimum":0},"sort_order":{"type":"integer"}}}},"required":["type","category_id","changes"]},{"type":"object","properties":{"budget_id":{"type":"string","format":"uuid"},"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000},"type":{"type":"string","enum":["create_transaction"]}},"required":["budget_id","amount","date","type"]},{"type":"object","properties":{"type":{"type":"string","enum":["update_transaction"]},"transaction_id":{"type":"string","format":"uuid"},"changes":{"type":"object","properties":{"category_id":{"type":["string","null"],"format":"uuid"},"subcategory_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"number","minimum":0},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"details":{"type":["string","null"],"maxLength":1000}}}},"required":["type","transaction_id","changes"]}]},"title":{"type":"string","minLength":1,"maxLength":160},"summary":{"type":"string","minLength":1,"maxLength":400},"confirmation_message":{"type":"string","minLength":1,"maxLength":400},"status":{"type":"string","enum":["pending","executed","cancelled","expired"]},"created_at":{"type":"string"},"resolved_at":{"type":["string","null"]},"executed_entity_type":{"type":["string","null"],"enum":["budget","category","transaction",null]},"executed_entity_id":{"type":["string","null"],"format":"uuid"}},"required":["id","conversation_id","message_id","action_type","action","title","summary","confirmation_message","status","created_at","resolved_at","executed_entity_type","executed_entity_id"]}}},"required":["conversation","messages","pending_actions"]}},"required":["data"]}},"text/event-stream":{"schema":{"type":"string","description":"newline-delimited SSE; see endpoint description for event names"}}}}}}},"/v1/api-keys":{"get":{"summary":"List API keys","description":"Returns metadata for each key (prefix, scopes, environment, expiry). Secrets are never returned after creation.","tags":["API keys"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"List of API keys (metadata only)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}},"required":["data"]}}}}}},"post":{"summary":"Create an API key","description":"Response includes the full `secret` **once**. Store it securely. Optional `expires_at` (ISO string or null) and `environment` default to server rules if omitted.","tags":["API keys"],"security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"environment":{"type":"string","enum":["live","test"]},"expires_at":{"type":["string","null"]}},"required":["name","scopes"]}}}},"responses":{"201":{"description":"Created API key (secret shown once)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ApiKeyCreated"}},"required":["data"]}}}}}}},"/v1/api-keys/{keyId}":{"delete":{"summary":"Revoke an API key","description":"Invalidates the key immediately. Existing requests with that bearer token will fail with `401`.","tags":["API keys"],"security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"keyId","in":"path"}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"]}},"required":["data"]}}}}}}}},"webhooks":{}}