{"openapi": "3.0.3", "info": {"title": "Pulsum API", "version": "v1", "description": "API de producto para finanzas personales y compartidas.", "license": {"name": "Uso interno de Pulsum", "url": "https://pulsum.cl/api/v1/docs/"}}, "servers": [{"url": "https://pulsum.cl", "description": "Servidor actual"}], "tags": [{"name": "Autenticaci\u00f3n", "description": "Inicio y cierre de sesiones de integraci\u00f3n."}, {"name": "Identidad", "description": "Identidad de la sesi\u00f3n autenticada."}, {"name": "Espacios", "description": "Espacios personales, compartidos y de grupo."}, {"name": "Miembros", "description": "Acceso de personas a espacios compartidos."}, {"name": "Personas", "description": "Personas que pagan o son responsables de gastos."}, {"name": "Categor\u00edas", "description": "Clasificaci\u00f3n de gastos."}, {"name": "Gastos", "description": "Captura, consulta, edici\u00f3n y trazabilidad de gastos."}, {"name": "Atajos", "description": "Flujos de captura r\u00e1pida para Apple Shortcuts."}, {"name": "Gastos fijos", "description": "Gastos fijos y recurrentes."}, {"name": "Presupuestos", "description": "Presupuestos mensuales por espacio."}, {"name": "Liquidaciones", "description": "Pagos y liquidaciones entre personas."}, {"name": "Reportes", "description": "Res\u00famenes financieros del espacio."}, {"name": "Notificaciones", "description": "Notificaciones de trabajo pendientes."}], "paths": {"/api/v1/auth/login/": {"post": {"tags": ["Autenticaci\u00f3n"], "summary": "Iniciar sesi\u00f3n", "operationId": "autenticacion_iniciar_sesion", "responses": {"200": {"description": "Sesi\u00f3n creada", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LoginResponse"}}}}, "400": {"$ref": "#/components/responses/ValidationError"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "429": {"$ref": "#/components/responses/RateLimited"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LoginInput"}}}}, "security": []}}, "/api/v1/auth/logout/": {"post": {"tags": ["Autenticaci\u00f3n"], "summary": "Cerrar sesi\u00f3n", "operationId": "autenticacion_cerrar_sesion", "responses": {"204": {"description": "Token revocado"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}}, "/api/v1/me/": {"get": {"tags": ["Identidad"], "summary": "Perfil actual", "operationId": "identidad_perfil_actual", "responses": {"200": {"description": "Perfil", "content": {"application/json": {"schema": {"type": "object", "properties": {"user": {"$ref": "#/components/schemas/User"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/": {"get": {"tags": ["Espacios"], "summary": "Listar espacios", "operationId": "espacios_listar_espacios", "responses": {"200": {"description": "Espacios", "content": {"application/json": {"schema": {"type": "object", "properties": {"projects": {"type": "array", "items": {"$ref": "#/components/schemas/Project"}}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "post": {"tags": ["Espacios"], "summary": "Crear espacio", "operationId": "espacios_crear_espacio", "responses": {"201": {"description": "Creado", "content": {"application/json": {"schema": {"type": "object", "properties": {"project": {"$ref": "#/components/schemas/Project"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProjectInput"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Espacios"], "summary": "Detalle de espacio", "operationId": "espacios_detalle_de_espacio", "responses": {"200": {"description": "Espacio", "content": {"application/json": {"schema": {"type": "object", "properties": {"project": {"$ref": "#/components/schemas/Project"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "patch": {"tags": ["Espacios"], "summary": "Actualizar espacio", "operationId": "espacios_actualizar_espacio", "responses": {"200": {"description": "Espacio actualizado"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProjectInput"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/members/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Miembros"], "summary": "Listar miembros", "operationId": "miembros_listar_miembros", "responses": {"200": {"description": "Miembros"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "post": {"tags": ["Miembros"], "summary": "Agregar o actualizar miembro", "operationId": "miembros_agregar_o_actualizar_miembro", "responses": {"201": {"description": "Miembro"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "required": ["identifier"], "properties": {"identifier": {"type": "string"}, "role": {"type": "string", "enum": ["admin", "editor", "viewer"]}}}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/members/{membership_id}/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}, {"name": "membership_id", "in": "path", "required": true, "description": "ID de la membres\u00eda", "schema": {"type": "integer", "minimum": 1}}], "patch": {"tags": ["Miembros"], "summary": "Actualizar miembro", "operationId": "miembros_actualizar_miembro", "responses": {"200": {"description": "Miembro actualizado"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"role": {"type": "string", "enum": ["admin", "editor", "viewer"]}}}}}}, "security": [{"bearerAuth": []}]}, "delete": {"tags": ["Miembros"], "summary": "Quitar miembro", "operationId": "miembros_quitar_miembro", "responses": {"204": {"description": "Miembro eliminado"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/people/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Personas"], "summary": "Listar pagadores", "operationId": "personas_listar_pagadores", "responses": {"200": {"description": "Personas"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "post": {"tags": ["Personas"], "summary": "Crear pagador", "operationId": "personas_crear_pagador", "responses": {"201": {"description": "Persona"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Person"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/people/{person_id}/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}, {"name": "person_id", "in": "path", "required": true, "description": "ID de la persona", "schema": {"type": "integer", "minimum": 1}}], "patch": {"tags": ["Personas"], "summary": "Actualizar pagador", "operationId": "personas_actualizar_pagador", "responses": {"200": {"description": "Persona actualizada"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Person"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/expense-form/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Gastos"], "summary": "Configuraci\u00f3n para captura m\u00f3vil", "operationId": "gastos_configuracion_para_captura_movil", "responses": {"200": {"description": "Opciones del formulario"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "description": "Endpoint compatible con el primer cliente iPhone. Para integraciones nuevas, usa los recursos de categor\u00edas y personas.", "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/expenses/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}, {"name": "Idempotency-Key", "in": "header", "description": "Clave \u00fanica por intento de creaci\u00f3n para evitar duplicados.", "schema": {"type": "string"}}], "post": {"tags": ["Gastos"], "summary": "Crear gasto para cliente m\u00f3vil", "operationId": "gastos_crear_gasto_para_cliente_movil", "responses": {"201": {"description": "Gasto creado"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "description": "Endpoint compatible con el primer cliente iPhone. Para integraciones nuevas, usa POST /api/v1/expenses/.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExpenseInput"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/shortcuts/personal-expense/": {"post": {"tags": ["Atajos"], "summary": "Registrar gasto personal r\u00e1pido", "operationId": "atajos_registrar_gasto_personal_rapido", "responses": {"201": {"description": "Gasto creado", "content": {"application/json": {"schema": {"type": "object", "properties": {"expense": {"$ref": "#/components/schemas/Expense"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "description": "Registra el gasto en la billetera personal de la sesi\u00f3n, en el per\u00edodo actual. No acepta un espacio compartido.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ShortcutPersonalExpenseInput"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/categories/": {"get": {"tags": ["Categor\u00edas"], "summary": "Listar categor\u00edas", "operationId": "categorias_listar_categorias", "responses": {"200": {"description": "Categor\u00edas"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "post": {"tags": ["Categor\u00edas"], "summary": "Crear categor\u00eda", "operationId": "categorias_crear_categoria", "responses": {"201": {"description": "Categor\u00eda", "content": {"application/json": {"schema": {"type": "object", "properties": {"category": {"$ref": "#/components/schemas/Category"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Category"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/categories/{category_id}/": {"parameters": [{"name": "category_id", "in": "path", "required": true, "description": "ID de la categor\u00eda", "schema": {"type": "integer", "minimum": 1}}], "patch": {"tags": ["Categor\u00edas"], "summary": "Actualizar categor\u00eda", "operationId": "categorias_actualizar_categoria", "responses": {"200": {"description": "Categor\u00eda actualizada"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Category"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/expenses/": {"get": {"tags": ["Gastos"], "summary": "Buscar gastos", "operationId": "gastos_buscar_gastos", "responses": {"200": {"description": "Gastos", "content": {"application/json": {"schema": {"type": "object", "properties": {"expenses": {"type": "array", "items": {"$ref": "#/components/schemas/Expense"}}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "parameters": [{"name": "project_id", "in": "query", "schema": {"type": "integer"}}, {"name": "month", "in": "query", "schema": {"type": "integer"}}, {"name": "year", "in": "query", "schema": {"type": "integer"}}, {"name": "q", "in": "query", "schema": {"type": "string"}}], "security": [{"bearerAuth": []}]}, "post": {"tags": ["Gastos"], "summary": "Crear gasto", "operationId": "gastos_crear_gasto", "responses": {"201": {"description": "Gasto creado", "content": {"application/json": {"schema": {"type": "object", "properties": {"expense": {"$ref": "#/components/schemas/Expense"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExpenseInput"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/expenses/recent/": {"get": {"tags": ["Gastos"], "summary": "Gastos recientes", "operationId": "gastos_gastos_recientes", "responses": {"200": {"description": "Gastos recientes", "content": {"application/json": {"schema": {"type": "object", "properties": {"expenses": {"type": "array", "items": {"$ref": "#/components/schemas/Expense"}}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "description": "Endpoint compatible con el primer cliente iPhone. Para listados filtrables, usa GET /api/v1/expenses/.", "security": [{"bearerAuth": []}]}}, "/api/v1/expenses/{expense_id}/": {"parameters": [{"name": "expense_id", "in": "path", "required": true, "description": "ID del gasto", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Gastos"], "summary": "Detalle de gasto", "operationId": "gastos_detalle_de_gasto", "responses": {"200": {"description": "Gasto", "content": {"application/json": {"schema": {"type": "object", "properties": {"expense": {"$ref": "#/components/schemas/Expense"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "patch": {"tags": ["Gastos"], "summary": "Editar gasto", "operationId": "gastos_editar_gasto", "responses": {"200": {"description": "Gasto actualizado"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExpenseInput"}}}}, "security": [{"bearerAuth": []}]}, "delete": {"tags": ["Gastos"], "summary": "Enviar gasto a papelera", "operationId": "gastos_enviar_gasto_a_papelera", "responses": {"204": {"description": "Eliminado"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}}, "/api/v1/expenses/{expense_id}/history/": {"parameters": [{"name": "expense_id", "in": "path", "required": true, "description": "ID del gasto", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Gastos"], "summary": "Historial del gasto", "operationId": "gastos_historial_del_gasto", "responses": {"200": {"description": "Historial"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}}, "/api/v1/expenses/{expense_id}/restore/": {"parameters": [{"name": "expense_id", "in": "path", "required": true, "description": "ID del gasto", "schema": {"type": "integer", "minimum": 1}}], "post": {"tags": ["Gastos"], "summary": "Recuperar gasto", "operationId": "gastos_recuperar_gasto", "responses": {"200": {"description": "Gasto recuperado"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/recurring-expenses/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Gastos fijos"], "summary": "Listar gastos fijos", "operationId": "gastos_fijos_listar_gastos_fijos", "responses": {"200": {"description": "Gastos fijos"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "post": {"tags": ["Gastos fijos"], "summary": "Crear gasto fijo", "operationId": "gastos_fijos_crear_gasto_fijo", "responses": {"201": {"description": "Gasto fijo"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecurringExpense"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/budgets/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Presupuestos"], "summary": "Consultar presupuestos", "operationId": "presupuestos_consultar_presupuestos", "responses": {"200": {"description": "Presupuestos"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "put": {"tags": ["Presupuestos"], "summary": "Guardar presupuesto", "operationId": "presupuestos_guardar_presupuesto", "responses": {"200": {"description": "Presupuesto"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BudgetInput"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/settlements/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Liquidaciones"], "summary": "Listar pagos", "operationId": "liquidaciones_listar_pagos", "responses": {"200": {"description": "Pagos"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}, "post": {"tags": ["Liquidaciones"], "summary": "Registrar pago", "operationId": "liquidaciones_registrar_pago", "responses": {"200": {"description": "Reintento idempotente; el pago ya exist\u00eda."}, "201": {"description": "Pago registrado."}, "409": {"description": "El per\u00edodo est\u00e1 cerrado, el pago supera la deuda o la clave ya se us\u00f3 con otro contenido.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "description": "Los clientes v1 pueden seguir enviando s\u00f3lo pagador, receptor, monto y date opcional. Integraciones nuevas deben enviar per\u00edodo e Idempotency-Key expl\u00edcitos.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SettlementInput"}}}}, "parameters": [{"name": "Idempotency-Key", "in": "header", "required": false, "description": "Clave recomendada para reintentos seguros. Debe coincidir con idempotency_key si se env\u00edan ambas.", "schema": {"type": "string", "maxLength": 64, "pattern": "^[A-Za-z0-9._:-]+$"}}], "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/settlements/{settlement_id}/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}, {"name": "settlement_id", "in": "path", "required": true, "description": "ID del pago", "schema": {"type": "integer", "minimum": 1}}], "delete": {"tags": ["Liquidaciones"], "summary": "Anular pago", "operationId": "liquidaciones_anular_pago", "responses": {"200": {"description": "Pago anulado o reintento idempotente."}, "409": {"description": "El per\u00edodo est\u00e1 cerrado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "description": "S\u00f3lo un administrador puede anularlo. El registro se conserva y el saldo pendiente se recalcula.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SettlementVoidInput"}}}}, "security": [{"bearerAuth": []}]}}, "/api/v1/projects/{project_id}/dashboard/": {"parameters": [{"name": "project_id", "in": "path", "required": true, "description": "ID del espacio", "schema": {"type": "integer", "minimum": 1}}], "get": {"tags": ["Reportes"], "summary": "Resumen financiero", "operationId": "reportes_resumen_financiero", "responses": {"200": {"description": "Panel financiero"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}}, "/api/v1/notifications/": {"get": {"tags": ["Notificaciones"], "summary": "Listar notificaciones", "operationId": "notificaciones_listar_notificaciones", "responses": {"200": {"description": "Notificaciones"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "security": [{"bearerAuth": []}]}}, "/api/v1/notifications/{notification_id}/": {"parameters": [{"name": "notification_id", "in": "path", "required": true, "description": "ID de notificaci\u00f3n", "schema": {"type": "integer", "minimum": 1}}], "patch": {"tags": ["Notificaciones"], "summary": "Marcar como le\u00edda", "operationId": "notificaciones_marcar_como_leida", "responses": {"200": {"description": "Notificaci\u00f3n"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "404": {"$ref": "#/components/responses/NotFound"}, "422": {"$ref": "#/components/responses/ValidationError"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"read": {"type": "boolean"}}}}}}, "security": [{"bearerAuth": []}]}}}, "components": {"securitySchemes": {"bearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "Opaque token"}}, "schemas": {"Error": {"type": "object", "required": ["error"], "properties": {"error": {"type": "object", "required": ["code", "message"], "properties": {"code": {"type": "string", "example": "validation_error"}, "message": {"type": "string", "example": "Corrige los campos indicados."}, "fields": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}}}}, "User": {"type": "object", "required": ["id", "username"], "properties": {"id": {"type": "integer"}, "username": {"type": "string"}, "email": {"type": "string", "format": "email"}, "display_name": {"type": "string"}}}, "Person": {"type": "object", "required": ["id", "name"], "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "email": {"type": "string", "format": "email", "nullable": true}, "user_id": {"type": "integer", "nullable": true}, "pet_style": {"type": "string", "enum": ["mara", "bruno"]}, "pet_mark": {"type": "string", "enum": ["flower", "beard"]}, "avatar": {"type": "string"}}}, "Project": {"type": "object", "required": ["id", "name", "kind", "sharing_policy"], "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "description": {"type": "string", "nullable": true}, "icon": {"type": "string"}, "color": {"type": "string"}, "kind": {"type": "string", "enum": ["individual", "shared", "group", "event"]}, "sharing_policy": {"type": "string", "enum": ["equal", "custom_percent", "communal"], "description": "custom_percent puede leerse y conservarse, pero se activa desde la administraci\u00f3n web porque requiere porcentajes que sumen 100%."}, "trusted_settlements": {"type": "boolean"}, "role": {"type": "string", "nullable": true}, "can_edit": {"type": "boolean"}, "can_admin": {"type": "boolean"}}}, "ProjectInput": {"type": "object", "required": ["name"], "properties": {"name": {"type": "string", "maxLength": 100}, "description": {"type": "string"}, "icon": {"type": "string", "maxLength": 12}, "color": {"type": "string", "example": "#0f766e"}, "kind": {"type": "string", "enum": ["individual", "shared", "group", "event"]}, "sharing_policy": {"type": "string", "enum": ["equal", "custom_percent", "communal"], "description": "La API no activa custom_percent sin reglas; config\u00faralo desde la administraci\u00f3n web."}}}, "Category": {"type": "object", "required": ["id", "name"], "properties": {"id": {"type": "integer"}, "name": {"type": "string", "maxLength": 100}}}, "Expense": {"type": "object", "required": ["id", "project", "amount", "accounting_period", "review_status"], "properties": {"id": {"type": "integer"}, "project": {"$ref": "#/components/schemas/Project"}, "amount": {"type": "string", "example": "12990.00"}, "gross_amount": {"type": "string", "example": "12990.00"}, "net_amount": {"type": "string", "example": "0.00"}, "reversal_status": {"type": "string", "enum": ["", "partial_refund", "refunded", "cancelled"]}, "reversal_status_label": {"type": "string"}, "reversal_date": {"type": "string", "format": "date", "nullable": true}, "reversal_note": {"type": "string"}, "currency": {"type": "string", "example": "CLP"}, "accounting_period": {"type": "object", "properties": {"month": {"type": "integer", "minimum": 1, "maximum": 12}, "year": {"type": "integer", "minimum": 2000}}}, "description": {"type": "string"}, "category": {"$ref": "#/components/schemas/Category", "nullable": true}, "payer": {"$ref": "#/components/schemas/Person", "nullable": true}, "responsible_person": {"$ref": "#/components/schemas/Person", "nullable": true}, "type": {"type": "string"}, "review_status": {"type": "string", "enum": ["pending", "reviewed", "accepted"]}, "review_status_label": {"type": "string"}, "source_date": {"type": "string", "format": "date", "nullable": true}, "created_at": {"type": "string", "format": "date-time", "nullable": true}}}, "ExpenseInput": {"type": "object", "required": ["project_id", "amount", "month", "year"], "properties": {"project_id": {"type": "integer"}, "amount": {"type": "string", "example": "12990"}, "month": {"type": "integer", "minimum": 1, "maximum": 12}, "year": {"type": "integer", "minimum": 2000}, "description": {"type": "string", "maxLength": 200}, "category_id": {"type": "integer", "nullable": true}, "new_category": {"type": "string"}, "payer_id": {"type": "integer", "nullable": true}, "responsible_person_id": {"type": "integer", "nullable": true}, "fully_paid_by_payer": {"type": "boolean"}}}, "RecurringExpense": {"type": "object", "required": ["id", "project_id", "description", "active"], "properties": {"id": {"type": "integer"}, "project_id": {"type": "integer"}, "category": {"$ref": "#/components/schemas/Category", "nullable": true}, "usage_type": {"type": "string"}, "description": {"type": "string"}, "expected_amount": {"type": "string", "nullable": true}, "payer": {"$ref": "#/components/schemas/Person", "nullable": true}, "active": {"type": "boolean"}}}, "BudgetInput": {"type": "object", "required": ["month", "year", "amount"], "properties": {"month": {"type": "integer", "minimum": 1, "maximum": 12}, "year": {"type": "integer"}, "amount": {"type": "string"}, "note": {"type": "string"}, "category_id": {"type": "integer", "nullable": true}}}, "SettlementInput": {"type": "object", "required": ["from_person_id", "to_person_id", "amount"], "properties": {"from_person_id": {"type": "integer"}, "to_person_id": {"type": "integer"}, "amount": {"type": "string", "example": "25000"}, "period_month": {"type": "integer", "minimum": 1, "maximum": 12, "description": "Recomendado. Debe enviarse junto a period_year; si ambos faltan se derivan de date o de la fecha local actual."}, "period_year": {"type": "integer", "minimum": 2000, "description": "Recomendado. Debe enviarse junto a period_month."}, "date": {"type": "string", "format": "date", "deprecated": true, "description": "Compatibilidad v1: fecha real del pago. Si falta el per\u00edodo, tambi\u00e9n se usa para derivarlo."}, "expense_id": {"type": "integer", "nullable": true}, "idempotency_key": {"type": "string", "maxLength": 64, "pattern": "^[A-Za-z0-9._:-]+$", "description": "Recomendado. Clave \u00fanica por intento; tambi\u00e9n puede enviarse en Idempotency-Key. Sin clave se aplica compatibilidad determinista obsoleta."}, "note": {"type": "string", "maxLength": 200}}}, "SettlementVoidInput": {"type": "object", "required": ["reason"], "properties": {"reason": {"type": "string", "minLength": 1, "maxLength": 240, "description": "Motivo auditable por el que el pago deja de descontar el saldo."}}}, "LoginInput": {"type": "object", "required": ["identifier", "password"], "properties": {"identifier": {"type": "string"}, "password": {"type": "string", "format": "password"}, "device_name": {"type": "string"}}}, "LoginResponse": {"type": "object", "required": ["token", "expires_at", "user"], "properties": {"token": {"type": "string"}, "token_type": {"type": "string", "example": "Bearer"}, "expires_at": {"type": "string", "format": "date-time"}, "user": {"$ref": "#/components/schemas/User"}}}, "ShortcutPersonalExpenseInput": {"type": "object", "required": ["amount", "category"], "properties": {"amount": {"type": "string", "example": "12990"}, "category": {"type": "string", "description": "Nombre de una categor\u00eda existente."}, "description": {"type": "string", "maxLength": 200}}}}, "responses": {"Unauthorized": {"description": "Token ausente, inv\u00e1lido, revocado o vencido.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "NotFound": {"description": "Recurso inexistente o no accesible.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "ValidationError": {"description": "Error de validaci\u00f3n.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "RateLimited": {"description": "Demasiados intentos de autenticaci\u00f3n.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}, "headers": {"Retry-After": {"description": "Segundos m\u00ednimos antes de reintentar.", "schema": {"type": "integer", "minimum": 1}}}}}}, "security": [{"bearerAuth": []}]}