{
    "version": "1.5.9",
    "generatedAt": "2026-07-25T09:53:37+00:00",
    "title": "API Restaurante — Cuchara para Pajaros",
    "description": "API REST compartida por el panel de meseros, futuras apps web y móviles. JSON UTF-8.",
    "baseUrl": "https:\/\/panel.cucharaparapajaros.com\/apis\/api.php\/",
    "contentType": "application\/json; charset=utf-8",
    "auth": {
        "type": "Bearer JWT (HS256)",
        "header": "Authorization: Bearer {token}",
        "login": "POST \/login con JSON { \"usuario\", \"contrasena\" } — devuelve token y datos del usuario.",
        "expiry": "El token expira en 7 días.",
        "publicRoutes": "Las rutas bajo \/public\/ no requieren token.",
        "permissions": "Algunas rutas exigen permisos RBAC (403 si no aplica). El login incluye permisos en sesión web; en API use el rol del usuario."
    },
    "conventions": [
        {
            "label": "Métodos",
            "text": "GET para consultas, POST para crear\/actualizar\/eliminar (no hay PUT\/DELETE)."
        },
        {
            "label": "Cuerpo",
            "text": "Enviar JSON en POST salvo descarga de PDF\/XML."
        },
        {
            "label": "Respuesta",
            "text": "JSON con success, message y datos según endpoint. Errores: 400, 401, 403, 404, 409, 500."
        },
        {
            "label": "CORS",
            "text": "Access-Control-Allow-Origin: * — usable desde web\/app externa."
        },
        {
            "label": "Estados",
            "text": "Muchos recursos usan estado A (activo), I (inactivo) o X (eliminado lógico). Inactivo oculta en pedidos pero conserva relaciones (ej. complementos vinculados a productos)."
        },
        {
            "label": "Totales de línea",
            "text": "total_linea = (precio_unitario + suma de complementos[].precio) × cantidad − descuento + tarrinas. Al crear\/actualizar, si complementos traen opcion_id el API completa precio desde el catálogo (no confía en precio 0 del cliente). Al recalcular (crear, editar, cobrar) también repara precios de complemento en 0 cuando el catálogo tiene valor > 0."
        }
    ],
    "groups": [
        {
            "id": "meta",
            "title": "Información general",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/",
                    "auth": "public",
                    "summary": "Health check \/ información del API",
                    "response": "{ \"success\": true, \"message\": \"API activa\" }"
                }
            ]
        },
        {
            "id": "auth",
            "title": "Autenticación y recuperación",
            "endpoints": [
                {
                    "method": "POST",
                    "path": "\/login",
                    "auth": "public",
                    "summary": "Iniciar sesión y obtener JWT",
                    "body": {
                        "usuario": "string (usuario o email)",
                        "contrasena": "string"
                    },
                    "response": "token, cod_usuario, cod_empresa, rol, permisos, nombre, email, expires…",
                    "example": "{\"usuario\":\"admin@correo.com\",\"contrasena\":\"***\"}"
                },
                {
                    "method": "POST",
                    "path": "\/recuperar_clave",
                    "auth": "public",
                    "summary": "Solicitar OTP de recuperación por correo",
                    "body": {
                        "email": "string"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/forgot_password",
                    "auth": "public",
                    "summary": "POST \/forgot_password"
                },
                {
                    "method": "POST",
                    "path": "\/verify_recovery_otp",
                    "auth": "public",
                    "summary": "Validar código OTP recibido por correo",
                    "body": {
                        "email": "string",
                        "otp": "string 6 dígitos"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/nueva_clave",
                    "auth": "public",
                    "summary": "Establecer nueva contraseña tras OTP válido",
                    "body": {
                        "email": "string",
                        "otp": "string",
                        "nueva_clave": "string"
                    }
                }
            ]
        },
        {
            "id": "public",
            "title": "Endpoints públicos (sin token)",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/public\/factura_sri\/pdf",
                    "auth": "public",
                    "summary": "GET \/public\/factura_sri\/pdf"
                },
                {
                    "method": "GET",
                    "path": "\/public\/factura_sri\/xml",
                    "auth": "public",
                    "summary": "GET \/public\/factura_sri\/xml"
                },
                {
                    "method": "GET",
                    "path": "\/public\/app\/bootstrap",
                    "auth": "public",
                    "summary": "GET \/public\/app\/bootstrap"
                },
                {
                    "method": "GET",
                    "path": "\/public\/app\/menu",
                    "auth": "public",
                    "summary": "GET \/public\/app\/menu"
                },
                {
                    "method": "GET",
                    "path": "\/public\/app\/sucursales",
                    "auth": "public",
                    "summary": "GET \/public\/app\/sucursales"
                },
                {
                    "method": "GET",
                    "path": "\/public\/app\/producto",
                    "auth": "public",
                    "summary": "GET \/public\/app\/producto"
                },
                {
                    "method": "POST",
                    "path": "\/public\/app\/mesa\/resolver",
                    "auth": "public",
                    "summary": "POST \/public\/app\/mesa\/resolver"
                },
                {
                    "method": "GET",
                    "path": "\/public\/app\/mesas",
                    "auth": "public",
                    "summary": "GET \/public\/app\/mesas"
                },
                {
                    "method": "POST",
                    "path": "\/public\/app\/pedido",
                    "auth": "public",
                    "summary": "POST \/public\/app\/pedido"
                },
                {
                    "method": "GET",
                    "path": "\/public\/web\/info",
                    "auth": "public",
                    "summary": "GET \/public\/web\/info"
                },
                {
                    "method": "POST",
                    "path": "\/public\/web\/contacto",
                    "auth": "public",
                    "summary": "POST \/public\/web\/contacto"
                },
                {
                    "method": "POST",
                    "path": "\/public\/web\/suscribir",
                    "auth": "public",
                    "summary": "POST \/public\/web\/suscribir"
                },
                {
                    "method": "POST",
                    "path": "\/public\/web\/reserva",
                    "auth": "public",
                    "summary": "POST \/public\/web\/reserva"
                },
                {
                    "method": "GET",
                    "path": "\/public\/pedido_factura",
                    "auth": "public",
                    "summary": "Contexto QR precuenta (datos pedido + cliente vinculado + reseña)",
                    "query": {
                        "id": "cod_pedido",
                        "token": "token público del QR"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/public\/pedido_factura\/buscar",
                    "auth": "public",
                    "summary": "Buscar cliente por documento (landing QR)",
                    "body": [
                        "id",
                        "token",
                        "tipo_identificacion",
                        "numero_identificacion"
                    ]
                },
                {
                    "method": "POST",
                    "path": "\/public\/pedido_factura\/guardar",
                    "auth": "public",
                    "summary": "Guardar datos factura + calificación cliente",
                    "body": "id, token, datos cliente, puntuacion (1-5), comentario"
                }
            ]
        },
        {
            "id": "perfil",
            "title": "Perfil de usuario",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/perfil",
                    "auth": "bearer",
                    "summary": "Perfil del usuario autenticado",
                    "permission": "Sesión activa"
                },
                {
                    "method": "POST",
                    "path": "\/perfil\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar perfil"
                }
            ]
        },
        {
            "id": "mesas",
            "title": "Mesas y plano",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/mesas",
                    "auth": "bearer+permiso",
                    "summary": "Listar mesas"
                },
                {
                    "method": "POST",
                    "path": "\/mesas\/crear",
                    "auth": "bearer+permiso",
                    "summary": "Crear registro en mesas"
                },
                {
                    "method": "POST",
                    "path": "\/mesas\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar mesas"
                },
                {
                    "method": "POST",
                    "path": "\/mesas\/eliminar",
                    "auth": "bearer+permiso",
                    "summary": "Eliminar mesas"
                },
                {
                    "method": "POST",
                    "path": "\/mesas\/toggle_activo",
                    "auth": "bearer+permiso",
                    "summary": "POST \/mesas\/toggle_activo"
                },
                {
                    "method": "POST",
                    "path": "\/mesas\/guardar_layout",
                    "auth": "bearer+permiso",
                    "summary": "POST \/mesas\/guardar_layout"
                },
                {
                    "method": "GET",
                    "path": "\/mesas\/plano_elementos",
                    "auth": "bearer",
                    "summary": "GET \/mesas\/plano_elementos"
                }
            ]
        },
        {
            "id": "zonas",
            "title": "Zonas del local",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/zonas",
                    "auth": "bearer",
                    "summary": "Listar zonas"
                },
                {
                    "method": "POST",
                    "path": "\/zonas\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en zonas"
                },
                {
                    "method": "POST",
                    "path": "\/zonas\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar zonas"
                },
                {
                    "method": "POST",
                    "path": "\/zonas\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar zonas"
                }
            ]
        },
        {
            "id": "reservas",
            "title": "Reservas",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/reservas",
                    "auth": "bearer",
                    "summary": "Listar reservas"
                },
                {
                    "method": "POST",
                    "path": "\/reservas\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en reservas"
                },
                {
                    "method": "POST",
                    "path": "\/reservas\/reenviar_correo",
                    "auth": "bearer",
                    "summary": "POST \/reservas\/reenviar_correo"
                },
                {
                    "method": "POST",
                    "path": "\/reservas\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar reservas"
                },
                {
                    "method": "POST",
                    "path": "\/reservas\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar reservas"
                }
            ]
        },
        {
            "id": "categorias",
            "title": "Categorías de menú",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/categorias",
                    "auth": "bearer",
                    "summary": "Listar categorias"
                },
                {
                    "method": "POST",
                    "path": "\/categorias\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en categorias"
                },
                {
                    "method": "POST",
                    "path": "\/categorias\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar categorias"
                },
                {
                    "method": "POST",
                    "path": "\/categorias\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar categorias"
                }
            ]
        },
        {
            "id": "productos",
            "title": "Productos",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/productos",
                    "auth": "bearer+permiso",
                    "summary": "Catálogo de productos activos",
                    "query": {
                        "q": "búsqueda opcional",
                        "categoria": "id categoría"
                    },
                    "permission": "productos.ver",
                    "response": "Incluye modifier_groups (solo grupos\/opciones activos) y complementos_grupos (todos los vínculos del producto)."
                },
                {
                    "method": "GET",
                    "path": "\/productos\/detalle",
                    "auth": "bearer+permiso",
                    "summary": "Detalle de productos"
                },
                {
                    "method": "POST",
                    "path": "\/productos\/crear",
                    "auth": "bearer+permiso",
                    "summary": "Crear registro en productos"
                },
                {
                    "method": "POST",
                    "path": "\/productos\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar productos"
                },
                {
                    "method": "POST",
                    "path": "\/productos\/divisiones\/guardar",
                    "auth": "bearer+permiso",
                    "summary": "POST \/productos\/divisiones\/guardar"
                },
                {
                    "method": "POST",
                    "path": "\/productos\/eliminar",
                    "auth": "bearer+permiso",
                    "summary": "Eliminar productos"
                }
            ]
        },
        {
            "id": "divisiones",
            "title": "Divisiones de producto",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/divisiones",
                    "auth": "bearer",
                    "summary": "Listar divisiones"
                },
                {
                    "method": "POST",
                    "path": "\/divisiones\/crear",
                    "auth": "bearer+permiso",
                    "summary": "Crear registro en divisiones"
                },
                {
                    "method": "POST",
                    "path": "\/divisiones\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar divisiones"
                },
                {
                    "method": "POST",
                    "path": "\/divisiones\/eliminar",
                    "auth": "bearer+permiso",
                    "summary": "Eliminar divisiones"
                }
            ]
        },
        {
            "id": "complementos",
            "title": "Complementos y opciones",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/complementos",
                    "auth": "bearer",
                    "summary": "Listar grupos de complementos de la empresa",
                    "query": {
                        "con_opciones": "1 para incluir opciones de cada grupo",
                        "todos": "1 para incluir grupos inactivos (I); por defecto solo excluye eliminados (X)"
                    },
                    "response": "complementos[] con id, nombre, maximo, minimo, descripcion, area, prep_bundle, mostrar_producto_estacion, estado (A|I|X), estado_label, opciones_count y opciones[] si aplica."
                },
                {
                    "method": "GET",
                    "path": "\/complementos\/detalle",
                    "auth": "bearer",
                    "summary": "Detalle de un grupo de complementos",
                    "query": {
                        "id": "id del grupo"
                    },
                    "response": "complemento con opciones[] (incluye inactivas I; excluye eliminadas X), productos[] vinculados {id, cod_producto, nombre, estado, estado_label} y productos_count."
                },
                {
                    "method": "POST",
                    "path": "\/complementos\/crear",
                    "auth": "bearer",
                    "summary": "Crear grupo de complementos",
                    "body": {
                        "nombre": "string obligatorio",
                        "maximo": "int (default 1)",
                        "minimo": "int (default 0)",
                        "descripcion": "string opcional",
                        "area": "string slugs separados por coma",
                        "prep_bundle": "string opcional — fusiona líneas en cocina",
                        "mostrar_producto_estacion": "0|1",
                        "estado": "A|I opcional (default A)"
                    },
                    "response": "complemento creado"
                },
                {
                    "method": "POST",
                    "path": "\/complementos\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar grupo de complementos",
                    "body": {
                        "id": "id del grupo",
                        "nombre, maximo, minimo, descripcion, area, prep_bundle, mostrar_producto_estacion": "opcionales",
                        "estado": "A activo (visible en pedidos) | I inactivo (oculto en pedidos, conserva vínculos con productos)"
                    },
                    "response": "complemento actualizado"
                },
                {
                    "method": "POST",
                    "path": "\/complementos\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar grupo de complementos (lógico, estado X)",
                    "body": {
                        "id": "id del grupo"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/complementos\/opciones\/crear",
                    "auth": "bearer",
                    "summary": "Agregar opción a un grupo",
                    "body": {
                        "cod_grupo": "int obligatorio",
                        "nombre": "string obligatorio",
                        "precio": "float (default 0)",
                        "area": "string opcional",
                        "estado": "A|I opcional (default A)"
                    },
                    "response": "opcion creada"
                },
                {
                    "method": "POST",
                    "path": "\/complementos\/opciones\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar opción de complemento",
                    "body": {
                        "id": "id de la opción",
                        "nombre, precio, area": "opcionales",
                        "estado": "A activo (visible en pedidos) | I inactivo"
                    },
                    "response": "opcion actualizada"
                },
                {
                    "method": "POST",
                    "path": "\/complementos\/opciones\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar opción (lógico, estado X)",
                    "body": {
                        "id": "id de la opción"
                    }
                }
            ]
        },
        {
            "id": "kitchen",
            "title": "Cocina (KDS)",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/kitchen\/areas",
                    "auth": "bearer+permiso",
                    "summary": "GET \/kitchen\/areas"
                },
                {
                    "method": "POST",
                    "path": "\/kitchen\/areas\/crear",
                    "auth": "bearer+permiso",
                    "summary": "POST \/kitchen\/areas\/crear"
                },
                {
                    "method": "POST",
                    "path": "\/kitchen\/areas\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "POST \/kitchen\/areas\/actualizar"
                },
                {
                    "method": "POST",
                    "path": "\/kitchen\/areas\/eliminar",
                    "auth": "bearer+permiso",
                    "summary": "POST \/kitchen\/areas\/eliminar"
                },
                {
                    "method": "GET",
                    "path": "\/kitchen\/tickets",
                    "auth": "bearer",
                    "summary": "GET \/kitchen\/tickets"
                },
                {
                    "method": "POST",
                    "path": "\/kitchen\/tickets\/estado",
                    "auth": "bearer",
                    "summary": "POST \/kitchen\/tickets\/estado"
                },
                {
                    "method": "POST",
                    "path": "\/kitchen\/pedidos\/preparar-todo",
                    "auth": "bearer",
                    "summary": "Marcar todos los tickets pending de un pedido como in_progress (atómico)",
                    "permission": "comandas.ver \/ pedidos.ver \/ estaciones",
                    "body": {
                        "cod_pedido": "int (id del pedido)"
                    },
                    "response": "data.updated_tickets, data.ticket_ids[]",
                    "notes": "Usado por el botón «Preparar todo» del tablero. Actualiza todos los tickets pending del pedido en una sola operación y alinea estado_cocina de las líneas. Evita la carrera de N POSTs por ítem."
                },
                {
                    "method": "GET",
                    "path": "\/kitchen\/motivos-cancelacion",
                    "auth": "bearer",
                    "summary": "GET \/kitchen\/motivos-cancelacion"
                },
                {
                    "method": "POST",
                    "path": "\/kitchen\/items\/estado",
                    "auth": "bearer",
                    "summary": "Cambiar el estado de cocina de una unidad de producto (por item_key)",
                    "permission": "comandas.ver \/ pedidos.ver \/ estaciones",
                    "body": {
                        "cod_pedido": "int",
                        "item_key": "clave de la unidad (kitchen_item_key)",
                        "estado": "pending|in_progress|ready|completed|delivered|cancelled"
                    },
                    "response": "data.updated_tickets, data.estado, data.pedido_totals, data.item_line_total, data.item_unit_price",
                    "notes": "El estado se aplica SOLO a los tickets con exactamente esa item_key (una unidad). Entregar\/completar un jugo u otro producto NUNCA actualiza tickets de otros ítems del mismo pedido; el ticket solo desaparece del tablero cuando TODAS las unidades activas están delivered. En líneas con cantidad > 1 cada unidad tiene su propia clave y su estado es independiente. El estado_cocina de la línea se agrega con weakest-link (el más atrasado de sus unidades). Para cancelled: use motivo (cod_motivo); cancela solo esa unidad, baja cantidad en 1, descuenta el empaque (tarrinas_qty) de esa unidad, recalcula total_linea y reasigna kitchen_item_key a la unidad sobreviviente (nunca cancela hermanas ni deja la línea apuntando al ticket cancelado)."
                },
                {
                    "method": "POST",
                    "path": "\/kitchen\/tickets\/cancelar",
                    "auth": "bearer",
                    "summary": "Cancelar ticket(s) de cocina con motivo",
                    "permission": "comandas.ver \/ pedidos.ver \/ estaciones",
                    "body": {
                        "ticket_ids": "int[] (opcional si se envía cod_pedido + item_key)",
                        "cod_pedido": "int",
                        "item_key": "clave de la unidad a cancelar",
                        "cod_motivo": "int requerido",
                        "motivo_otro": "string si el motivo requiere detalle"
                    },
                    "response": "data.cancelled_tickets, data.pedidos_actualizados, data.pedido_totals",
                    "notes": "Cancela únicamente los tickets de la unidad indicada (ticket_ids y\/o item_key). En líneas con cantidad > 1: reduce cantidad en 1, resta tarrinas_qty de esa unidad (desde payload o reparto), recalcula total_linea por componentes, conserva hermanas activas y actualiza kitchen_item_key al sobreviviente. Evita dejar empaque huérfano (+$0.25, etc.). No expandir a todas las claves de la línea."
                },
                {
                    "method": "POST",
                    "path": "\/kitchen\/tickets\/vaciar-cancelados",
                    "auth": "bearer",
                    "summary": "POST \/kitchen\/tickets\/vaciar-cancelados"
                }
            ]
        },
        {
            "id": "clientes",
            "title": "Clientes",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/clientes",
                    "auth": "bearer",
                    "summary": "Listar clientes"
                },
                {
                    "method": "GET",
                    "path": "\/clientes\/detalle",
                    "auth": "bearer",
                    "summary": "Detalle de clientes"
                },
                {
                    "method": "POST",
                    "path": "\/clientes\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en clientes"
                },
                {
                    "method": "POST",
                    "path": "\/clientes\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar clientes"
                },
                {
                    "method": "POST",
                    "path": "\/clientes\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar clientes"
                }
            ]
        },
        {
            "id": "pedidos",
            "title": "Pedidos, cobros y facturación",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/pedidos",
                    "auth": "bearer",
                    "summary": "Listado de pedidos del día \/ filtros",
                    "query": {
                        "fecha": "YYYY-MM-DD (por defecto hoy en finalizada\/cancelado)",
                        "estado": "servicio | finalizada | cancelado (solo ADMIN) | …",
                        "page": "paginación (finalizada y cancelado)"
                    },
                    "response": "Pedidos con estado_pedido, saldo_pendiente, pedido_abierto (true si cobró pero sigue abierto para más ítems). estado=cancelado requiere rol ADMIN."
                },
                {
                    "method": "GET",
                    "path": "\/pedidos\/facturas",
                    "auth": "bearer",
                    "summary": "GET \/pedidos\/facturas"
                },
                {
                    "method": "GET",
                    "path": "\/pedidos\/facturas\/sri",
                    "auth": "bearer",
                    "summary": "GET \/pedidos\/facturas\/sri"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/facturas\/enviar_sri",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/facturas\/enviar_sri"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/facturas\/anular_sri",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/facturas\/anular_sri"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/facturas\/reenviar_sri",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/facturas\/reenviar_sri"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/facturas\/enviar_correo",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/facturas\/enviar_correo"
                },
                {
                    "method": "GET",
                    "path": "\/pedidos\/detalle",
                    "auth": "bearer",
                    "summary": "Detalle de pedidos"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/crear",
                    "auth": "bearer",
                    "summary": "Crear pedido (mesa, delivery, pickup)",
                    "body": "tipo_pedido, cod_mesa, items[] (precio_unitario base + complementos[] con opcion_id\/precio + tarrinas_*), cliente…",
                    "notes": "Tras insertar, recalcula total_linea\/subtotal igual que actualizar. Los precios de complementos con opcion_id se toman del catálogo si el cliente envía 0 o incompleto."
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/eliminar",
                    "auth": "bearer",
                    "summary": "Cancelar pedido en servicio o eliminar pedido finalizado",
                    "permission": "Solo rol ADMIN",
                    "body": {
                        "id": "cod_pedido",
                        "cod_motivo": "requerido al cancelar pedido en servicio",
                        "motivo_otro": "opcional según motivo"
                    },
                    "response": "pedido cancelado o eliminado según estado",
                    "notes": "Pedidos en servicio pasan a estado_pedido cancelado. Pedidos finalizados\/pagados se eliminan del listado (solo ADMIN)."
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/actualizar",
                    "auth": "bearer",
                    "summary": "Editar pedido existente (items, mesa, cliente, notas)",
                    "body": {
                        "id": "cod_pedido",
                        "items": "array completo de líneas: cada línea vigente con su id; {id, eliminar: 1} para borrar; sin id = línea nueva. Una línea de cantidad > 1 puede llegar como varias unidades con el MISMO id (cantidad 1 c\/u): el API las re-agrupa sumando cantidades, no se colapsa a 1.",
                        "tipo_pedido \/ cod_mesa \/ cliente…": "opcionales, se conserva el valor actual si no se envían"
                    },
                    "response": "pedido actualizado con items y kitchen_sync {created, cancelled, updated_notes}",
                    "notes": "Toda línea vigente debe venir en items (con eliminar: 1 si se borra), si falta alguna se rechaza. GET \/pedidos expone las líneas con cantidad > 1 expandidas en unidades (una por ticket de cocina) que comparten el id de la línea; al guardar, esas unidades se re-agrupan por id (se suman cantidades\/tarrinas) para no perder unidades. Meseros: las líneas ya enviadas a cocina o cobradas no se pueden reescribir ni eliminar (solo nota de dueño y tarrinas\/para llevar). ADMIN: puede reescribir (cantidad, producto, complementos) y eliminar líneas ya enviadas a cocina — los tickets se resincronizan cancelando huérfanos y creando las unidades nuevas, conservando el estado de cocina de la línea; las líneas cobradas (linea_cobrada=1) siguen bloqueadas hasta revertir el cobro. Pedidos finalizados solo los edita ADMIN. Precios de línea: ver convención Totales de línea (complementos por opcion_id desde catálogo)."
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/actualizar_cliente",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/actualizar_cliente"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/comprobante",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/comprobante"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/items\/asignar",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/items\/asignar"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/documento\/enlace",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/documento\/enlace"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/factura\/enlace",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/factura\/enlace"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/pickup\/whatsapp",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/pickup\/whatsapp"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/documento\/enviar_correo",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/documento\/enviar_correo"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/cobrar",
                    "auth": "bearer",
                    "summary": "Registrar cobro del pedido (no cierra el pedido)",
                    "permission": "Rol\/permiso de cobro",
                    "body": {
                        "id": "cod_pedido",
                        "formas_pago": "array según modal de cobro",
                        "pago_detalle.cuenta_dividida": "nombre de la persona (cuenta dividida)",
                        "documento": "factura\/nota según configuración"
                    },
                    "response": "pedido con estado_pedido pagado, pedido_abierto: true, cobro_parcial si aplica. Marca linea_cobrada en ítems cobrados. La mesa no se libera hasta finalizar.",
                    "notes": "Cuenta dividida: debe cobrar el saldo exacto de esa persona (sin abonos parciales por cuenta). El saldo se calcula desde la suma de ítems pendientes de esa persona (misma base que el modal), no desde un subtotal de encabezado desfasado tras cancelaciones. IVA incluido \/ sin servicio-delivery: saldo = subtotal pendiente de la persona."
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/convertir_factura\/preview",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/convertir_factura\/preview"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/convertir_factura",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/convertir_factura"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/revertir-cobro",
                    "auth": "bearer",
                    "summary": "POST \/pedidos\/revertir-cobro"
                },
                {
                    "method": "POST",
                    "path": "\/pedidos\/finalizar",
                    "auth": "bearer",
                    "summary": "Cerrar pedido tras cobro completo (libera mesa)",
                    "permission": "Mismo permiso que cobrar",
                    "body": {
                        "id": "cod_pedido"
                    },
                    "response": "pedido con estado_pedido finalizada, pedido_abierto: false",
                    "notes": "Requiere: saldo 0, cobro completo (o todas las cuentas en split pagadas), y todos los ítems de cocina en delivered (Entregado). Las líneas sueltas de embalaje (Tarrina\/Vaso) no van a estaciones y no bloquean finalizar. No aplica a pedidos cancelados o ya finalizados."
                }
            ]
        },
        {
            "id": "cupones",
            "title": "Cupones",
            "endpoints": [
                {
                    "method": "POST",
                    "path": "\/cupones\/validar",
                    "auth": "bearer",
                    "summary": "POST \/cupones\/validar"
                },
                {
                    "method": "GET",
                    "path": "\/cupones",
                    "auth": "bearer",
                    "summary": "Listar cupones"
                },
                {
                    "method": "POST",
                    "path": "\/cupones\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en cupones"
                },
                {
                    "method": "POST",
                    "path": "\/cupones\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar cupones"
                },
                {
                    "method": "POST",
                    "path": "\/cupones\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar cupones"
                }
            ]
        },
        {
            "id": "servicios",
            "title": "Servicios adicionales",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/servicios",
                    "auth": "bearer+permiso",
                    "summary": "Listar servicios"
                },
                {
                    "method": "GET",
                    "path": "\/servicios\/detalle",
                    "auth": "bearer+permiso",
                    "summary": "Detalle de servicios"
                },
                {
                    "method": "POST",
                    "path": "\/servicios\/crear",
                    "auth": "bearer+permiso",
                    "summary": "Crear registro en servicios"
                },
                {
                    "method": "POST",
                    "path": "\/servicios\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar servicios"
                },
                {
                    "method": "POST",
                    "path": "\/servicios\/eliminar",
                    "auth": "bearer+permiso",
                    "summary": "Eliminar servicios"
                }
            ]
        },
        {
            "id": "proformas",
            "title": "Proformas",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/proformas",
                    "auth": "bearer+permiso",
                    "summary": "Listar proformas"
                },
                {
                    "method": "GET",
                    "path": "\/proformas\/detalle",
                    "auth": "bearer+permiso",
                    "summary": "Detalle de proformas"
                },
                {
                    "method": "POST",
                    "path": "\/proformas\/crear",
                    "auth": "bearer+permiso",
                    "summary": "Crear registro en proformas"
                },
                {
                    "method": "POST",
                    "path": "\/proformas\/marcar-enviada",
                    "auth": "bearer+permiso",
                    "summary": "POST \/proformas\/marcar-enviada"
                },
                {
                    "method": "GET",
                    "path": "\/proformas\/historial",
                    "auth": "bearer+permiso",
                    "summary": "GET \/proformas\/historial"
                },
                {
                    "method": "GET",
                    "path": "\/proformas\/pdf",
                    "auth": "bearer+permiso",
                    "summary": "GET \/proformas\/pdf"
                },
                {
                    "method": "GET",
                    "path": "\/proformas\/adjunto",
                    "auth": "bearer+permiso",
                    "summary": "GET \/proformas\/adjunto"
                },
                {
                    "method": "POST",
                    "path": "\/proformas\/adjuntos",
                    "auth": "bearer+permiso",
                    "summary": "POST \/proformas\/adjuntos"
                },
                {
                    "method": "POST",
                    "path": "\/proformas\/facturar",
                    "auth": "bearer+permiso",
                    "summary": "POST \/proformas\/facturar"
                },
                {
                    "method": "POST",
                    "path": "\/proformas\/eliminar",
                    "auth": "bearer+permiso",
                    "summary": "Eliminar proformas"
                },
                {
                    "method": "POST",
                    "path": "\/proformas\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar proformas"
                },
                {
                    "method": "POST",
                    "path": "\/proformas\/estado",
                    "auth": "bearer+permiso",
                    "summary": "POST \/proformas\/estado"
                },
                {
                    "method": "POST",
                    "path": "\/proformas\/enviar-correo",
                    "auth": "bearer+permiso",
                    "summary": "POST \/proformas\/enviar-correo"
                }
            ]
        },
        {
            "id": "equipo_usuarios",
            "title": "Equipo \/ usuarios",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/equipo_usuarios",
                    "auth": "bearer+permiso",
                    "summary": "Listar equipo usuarios"
                },
                {
                    "method": "POST",
                    "path": "\/equipo_usuarios\/crear",
                    "auth": "bearer+permiso",
                    "summary": "Crear registro en equipo usuarios"
                },
                {
                    "method": "POST",
                    "path": "\/equipo_usuarios\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar equipo usuarios"
                },
                {
                    "method": "POST",
                    "path": "\/equipo_usuarios\/desactivar",
                    "auth": "bearer+permiso",
                    "summary": "POST \/equipo_usuarios\/desactivar"
                }
            ]
        },
        {
            "id": "roles",
            "title": "Roles y permisos",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/roles",
                    "auth": "bearer+permiso",
                    "summary": "Roles y catálogo de permisos RBAC",
                    "permission": "roles.gestionar"
                },
                {
                    "method": "POST",
                    "path": "\/roles\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar roles"
                }
            ]
        },
        {
            "id": "repartidores",
            "title": "Repartidores delivery",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/repartidores",
                    "auth": "bearer",
                    "summary": "Listar repartidores"
                },
                {
                    "method": "POST",
                    "path": "\/repartidores\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en repartidores"
                },
                {
                    "method": "POST",
                    "path": "\/repartidores\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar repartidores"
                },
                {
                    "method": "POST",
                    "path": "\/repartidores\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar repartidores"
                }
            ]
        },
        {
            "id": "trabajadores",
            "title": "Trabajadores, turnos y nómina",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/trabajadores\/cargos",
                    "auth": "bearer",
                    "summary": "GET \/trabajadores\/cargos"
                },
                {
                    "method": "GET",
                    "path": "\/trabajadores\/estado",
                    "auth": "bearer",
                    "summary": "GET \/trabajadores\/estado"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en trabajadores"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar trabajadores"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar trabajadores"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/turnos\/asignar",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/turnos\/asignar"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/turnos\/quitar",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/turnos\/quitar"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/turnos\/copiar_semana",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/turnos\/copiar_semana"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/adelantos\/crear",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/adelantos\/crear"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/adelantos\/aplicar_cuota",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/adelantos\/aplicar_cuota"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/adelantos\/actualizar",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/adelantos\/actualizar"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/adelantos\/eliminar",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/adelantos\/eliminar"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/bonos\/crear",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/bonos\/crear"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/bonos\/actualizar",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/bonos\/actualizar"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/bonos\/eliminar",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/bonos\/eliminar"
                },
                {
                    "method": "GET",
                    "path": "\/trabajadores\/asistencias",
                    "auth": "bearer",
                    "summary": "GET \/trabajadores\/asistencias"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/asistencias\/guardar",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/asistencias\/guardar"
                },
                {
                    "method": "GET",
                    "path": "\/trabajadores\/roles_pago",
                    "auth": "bearer",
                    "summary": "GET \/trabajadores\/roles_pago"
                },
                {
                    "method": "GET",
                    "path": "\/trabajadores\/roles_pago\/historial",
                    "auth": "bearer",
                    "summary": "GET \/trabajadores\/roles_pago\/historial"
                },
                {
                    "method": "GET",
                    "path": "\/trabajadores\/roles_pago\/detalle",
                    "auth": "bearer",
                    "summary": "GET \/trabajadores\/roles_pago\/detalle"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/roles_pago\/generar",
                    "auth": "bearer",
                    "summary": "POST \/trabajadores\/roles_pago\/generar"
                },
                {
                    "method": "POST",
                    "path": "\/trabajadores\/roles_pago\/pagar",
                    "auth": "bearer",
                    "summary": "Marcar un rol de pago semanal como pagado y registrar el gasto de nómina",
                    "body": {
                        "id": "int id del rol",
                        "metodo_pago": "efectivo|transferencia (default efectivo)"
                    },
                    "response": "rol actualizado con estado pagado",
                    "notes": "Rechaza si el rol ya está pagado o si total_recibir es <= 0 (no permite pagar roles en cero). Solo crea gasto de nómina cuando hay monto a pagar. Aplica cuotas de adelantos\/descuentos del detalle del rol."
                }
            ]
        },
        {
            "id": "caja_chica",
            "title": "Caja chica",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/caja_chica\/encargados",
                    "auth": "bearer",
                    "summary": "GET \/caja_chica\/encargados"
                },
                {
                    "method": "GET",
                    "path": "\/caja_chica\/estado",
                    "auth": "bearer",
                    "summary": "GET \/caja_chica\/estado"
                },
                {
                    "method": "GET",
                    "path": "\/caja_chica\/metricas_mes",
                    "auth": "bearer",
                    "summary": "GET \/caja_chica\/metricas_mes"
                },
                {
                    "method": "GET",
                    "path": "\/caja_chica\/historial",
                    "auth": "bearer",
                    "summary": "GET \/caja_chica\/historial"
                },
                {
                    "method": "GET",
                    "path": "\/caja_chica\/turnos_reporte",
                    "auth": "bearer",
                    "summary": "Turnos de caja de una fecha para generar reporte de cuadre",
                    "permission": "negocio.ver o caja chica",
                    "query": {
                        "fecha": "YYYY-MM-DD (default hoy)"
                    },
                    "response": "turnos[] con id, turnoNombre, turnoLabel (nombre + rango real), rangoReal {inicio, fin, label}, usuarios[] {nombre, primerHora, ultimaHora, rangoLabel}, balance, estado (abierto|cerrado)",
                    "notes": "El rango real se calcula desde el primer movimiento (apertura, venta, ingreso, egreso o gasto) hasta el último. En turnos cerrados las ventas se filtran por fecha_apertura y fecha_cierre. En turnos abiertos se incluyen todas las ventas del día desde la apertura (sin tope del horario configurado del turno). El primer turno del día también absorbe las ventas cobradas antes de su apertura (ej. pedidos de la mañana cobrados antes de abrir la caja), para que no queden fuera de todos los turnos."
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/turnos\/eliminar",
                    "auth": "bearer",
                    "summary": "POST \/caja_chica\/turnos\/eliminar"
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/abrir",
                    "auth": "bearer",
                    "summary": "POST \/caja_chica\/abrir"
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/encargado",
                    "auth": "bearer",
                    "summary": "POST \/caja_chica\/encargado"
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/movimientos\/crear",
                    "auth": "bearer",
                    "summary": "Registrar ingreso o retiro de efectivo del turno abierto",
                    "permission": "Encargado del turno o ADMIN\/negocio.ver",
                    "body": {
                        "cod_caja_chica": "int (turno abierto)",
                        "tipo": "ingreso|retiro",
                        "concepto": "string",
                        "monto": "decimal > 0",
                        "notas": "texto opcional"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/movimientos\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar ingreso o retiro de efectivo del turno abierto (baja lógica)",
                    "permission": "Encargado del turno o ADMIN\/negocio.ver",
                    "body": {
                        "id": "int"
                    },
                    "notes": "Solo en turno abierto."
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/movimientos\/actualizar",
                    "auth": "bearer",
                    "summary": "Editar ingreso o retiro de efectivo del turno abierto",
                    "permission": "Encargado del turno o ADMIN\/negocio.ver",
                    "body": {
                        "id": "int",
                        "tipo": "ingreso|retiro",
                        "concepto": "string",
                        "monto": "decimal > 0",
                        "notas": "texto opcional"
                    },
                    "notes": "Solo en turno abierto. El ADMIN también puede editar aunque no sea el encargado."
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/gastos\/crear",
                    "auth": "bearer",
                    "summary": "Registrar un gasto del turno de caja abierto",
                    "permission": "Encargado del turno o ADMIN\/negocio.ver",
                    "body": {
                        "cod_caja_chica": "int (turno abierto)",
                        "concepto": "string",
                        "monto": "decimal > 0",
                        "notas": "HTML\/texto opcional"
                    },
                    "notes": "Solo en turno abierto. El gasto queda ligado al turno (cod_caja_chica) y descuenta del balance de caja."
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/gastos\/actualizar",
                    "auth": "bearer",
                    "summary": "Editar un gasto del turno de caja abierto",
                    "permission": "Encargado del turno o ADMIN\/negocio.ver",
                    "body": {
                        "id": "int",
                        "concepto": "string",
                        "monto": "decimal > 0",
                        "notas": "HTML\/texto opcional"
                    },
                    "notes": "Solo se pueden editar gastos cuyo turno siga abierto. El ADMIN (o quien tenga negocio.ver) también puede editar aunque no sea el encargado."
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/gastos\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar un gasto del turno de caja abierto (baja lógica)",
                    "permission": "Encargado del turno o ADMIN\/negocio.ver",
                    "body": {
                        "id": "int"
                    },
                    "notes": "Solo se pueden eliminar gastos cuyo turno siga abierto. Actualiza el balance de caja."
                },
                {
                    "method": "GET",
                    "path": "\/caja_chica\/ventas_manuales\/listar",
                    "auth": "bearer",
                    "summary": "Listado de ventas manuales (pedidos fuera del sistema)",
                    "permission": "ADMIN o negocio.ver",
                    "query": {
                        "fecha_desde": "YYYY-MM-DD opcional",
                        "fecha_hasta": "YYYY-MM-DD opcional"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/ventas_manuales\/crear",
                    "auth": "bearer",
                    "summary": "Registrar venta manual",
                    "permission": "ADMIN o negocio.ver",
                    "body": {
                        "fecha": "YYYY-MM-DD",
                        "hora": "HH:mm",
                        "monto": "decimal",
                        "motivo": "HTML\/texto"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/ventas_manuales\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar venta manual",
                    "permission": "ADMIN o negocio.ver",
                    "body": {
                        "id": "int",
                        "fecha": "YYYY-MM-DD",
                        "hora": "HH:mm",
                        "monto": "decimal",
                        "motivo": "HTML\/texto"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/ventas_manuales\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar venta manual (baja lógica)",
                    "permission": "ADMIN o negocio.ver",
                    "body": {
                        "id": "int"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/caja_chica\/cerrar",
                    "auth": "bearer",
                    "summary": "POST \/caja_chica\/cerrar"
                }
            ]
        },
        {
            "id": "turnos_atencion",
            "title": "Turnos de atención",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/turnos_atencion",
                    "auth": "bearer",
                    "summary": "Listar turnos atencion"
                },
                {
                    "method": "GET",
                    "path": "\/turnos_atencion\/puede_inactivar",
                    "auth": "bearer",
                    "summary": "GET \/turnos_atencion\/puede_inactivar"
                },
                {
                    "method": "POST",
                    "path": "\/turnos_atencion\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en turnos atencion"
                },
                {
                    "method": "POST",
                    "path": "\/turnos_atencion\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar turnos atencion"
                }
            ]
        },
        {
            "id": "kpis_diarios",
            "title": "KPIs diarios",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/kpis_diarios",
                    "auth": "bearer+permiso",
                    "summary": "Panel KPIs del día (ventas, mesas, reseñas, etc.)",
                    "permission": "inicio.ver",
                    "query": {
                        "fecha": "YYYY-MM-DD opcional"
                    }
                }
            ]
        },
        {
            "id": "gastos_empresa",
            "title": "Negocio \/ gastos empresa",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/gastos_empresa\/resumen",
                    "auth": "bearer+permiso",
                    "summary": "Resumen mensual negocio (KPIs, gastos, reseñas)",
                    "permission": "negocio.ver",
                    "query": {
                        "anio": "int",
                        "mes": "1-12"
                    }
                },
                {
                    "method": "POST",
                    "path": "\/gastos_empresa\/crear",
                    "auth": "bearer+permiso",
                    "summary": "Crear registro en gastos empresa"
                },
                {
                    "method": "POST",
                    "path": "\/gastos_empresa\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar gastos empresa"
                },
                {
                    "method": "POST",
                    "path": "\/gastos_empresa\/eliminar",
                    "auth": "bearer+permiso",
                    "summary": "Eliminar gastos empresa"
                }
            ]
        },
        {
            "id": "proveedores",
            "title": "Proveedores",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/proveedores",
                    "auth": "bearer",
                    "summary": "Listar proveedores"
                },
                {
                    "method": "POST",
                    "path": "\/proveedores\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en proveedores"
                },
                {
                    "method": "POST",
                    "path": "\/proveedores\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar proveedores"
                },
                {
                    "method": "POST",
                    "path": "\/proveedores\/eliminar",
                    "auth": "bearer",
                    "summary": "Eliminar proveedores"
                }
            ]
        },
        {
            "id": "sucursales",
            "title": "Sucursales",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/sucursales",
                    "auth": "bearer",
                    "summary": "Listar sucursales"
                },
                {
                    "method": "POST",
                    "path": "\/sucursales\/crear",
                    "auth": "bearer",
                    "summary": "Crear registro en sucursales"
                },
                {
                    "method": "POST",
                    "path": "\/sucursales\/actualizar",
                    "auth": "bearer",
                    "summary": "Actualizar sucursales"
                }
            ]
        },
        {
            "id": "empresa",
            "title": "Configuración empresa",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/empresa\/kitchen-pantallas",
                    "auth": "bearer+permiso",
                    "summary": "GET \/empresa\/kitchen-pantallas"
                },
                {
                    "method": "GET",
                    "path": "\/empresa",
                    "auth": "bearer+permiso",
                    "summary": "Listar empresa"
                },
                {
                    "method": "GET",
                    "path": "\/empresa\/bancos",
                    "auth": "bearer",
                    "summary": "GET \/empresa\/bancos"
                },
                {
                    "method": "POST",
                    "path": "\/empresa\/actualizar",
                    "auth": "bearer+permiso",
                    "summary": "Actualizar empresa"
                },
                {
                    "method": "GET",
                    "path": "\/empresa\/cartas",
                    "auth": "bearer+permiso",
                    "summary": "GET \/empresa\/cartas"
                },
                {
                    "method": "POST",
                    "path": "\/empresa\/cartas\/eliminar",
                    "auth": "bearer+permiso",
                    "summary": "POST \/empresa\/cartas\/eliminar"
                }
            ]
        },
        {
            "id": "accesos_log",
            "title": "Log de accesos",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/accesos_log",
                    "auth": "bearer",
                    "summary": "Listar accesos log"
                }
            ]
        },
        {
            "id": "logout",
            "title": "Logout",
            "endpoints": [
                {
                    "method": "POST",
                    "path": "\/logout",
                    "auth": "bearer",
                    "summary": "POST \/logout"
                }
            ]
        },
        {
            "id": "cms",
            "title": "Cms",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/cms\/contactos",
                    "auth": "bearer+permiso",
                    "summary": "GET \/cms\/contactos"
                },
                {
                    "method": "POST",
                    "path": "\/cms\/contactos\/estado",
                    "auth": "bearer+permiso",
                    "summary": "POST \/cms\/contactos\/estado"
                },
                {
                    "method": "GET",
                    "path": "\/cms\/suscripciones",
                    "auth": "bearer+permiso",
                    "summary": "GET \/cms\/suscripciones"
                }
            ]
        },
        {
            "id": "app",
            "title": "App",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/app\/perfiles",
                    "auth": "bearer",
                    "summary": "GET \/app\/perfiles"
                }
            ]
        },
        {
            "id": "mis-sucursales",
            "title": "Mis-sucursales",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/mis-sucursales",
                    "auth": "bearer",
                    "summary": "Listar mis-sucursales"
                }
            ]
        },
        {
            "id": "pruebas",
            "title": "Pruebas",
            "endpoints": [
                {
                    "method": "GET",
                    "path": "\/pruebas\/resumen",
                    "auth": "bearer",
                    "summary": "GET \/pruebas\/resumen"
                },
                {
                    "method": "POST",
                    "path": "\/pruebas\/reset",
                    "auth": "bearer",
                    "summary": "POST \/pruebas\/reset"
                }
            ]
        }
    ],
    "routeCount": 206
}