Skip to content

Tenants

Tenants

Prefijo: /api/tenants
Requiere Auth: Sí (excepto register-tenant)
Permiso requerido: tenants, *

Sistema completo de gestión multi-tenant. NeoPOS es una arquitectura multi-tenant pura: cada tenant representa una organización/empresa independiente con su propio aislamiento de datos. Todos los endpoints de negocio filtran automáticamente por tenant_id del JWT.

Roles involucrados:

RolAcceso a Tenants
Superadmin (rol=3)Gestión completa: crear, listar, editar, eliminar tenants, ver métricas, actividad y dashboard global
Admin (rol=1)Ve SU propio tenant vía GET /api/tenants/current, GET /api/tenants/:tenant_id, GET /api/tenants/:tenant_id/metrics y GET /api/admin/tenants/:tenant_id/activity (solo si tenant_id del path == tenant_id del JWT). No tiene acceso cross-tenant
Asistente (rol=2)No tiene acceso a gestión de tenants

Ciclo de Vida de un Tenant

1. Registro (self-service) → POST /api/auth/register-tenant
2. Creación (Superadmin) → POST /api/tenants
3. Configuración → PUT /api/tenants/:id
4. Monitoreo → GET /api/tenants/:id/metrics
5. Dashboard Global → GET /api/admin/dashboard/overview
6. Eliminación → DELETE /api/tenants/:id

Planes y Facturación

Planes Disponibles

Planplanlimite_usuariosDescripción
BásicoBASICO3Plan inicial para negocios pequeños
ProfesionalPRO10Funcionalidades completas para restaurantes
PremiumPREMIUMIlimitadoTodos los módulos y soporte prioritario
EnterpriseENTERPRISEIlimitadoOn-premise / dedicado, SLA personalizado

Estados de un Tenant

EstadoestadoSignificado
ActivoACTIVOFuncionando normalmente
InactivoINACTIVOSuspendido temporalmente (no puede operar)
SuspendidoSUSPENDIDOSuspendido por impago o incumplimiento
CanceladoCANCELADOCuenta cancelada definitivamente

Control de expiración

El campo fecha_expiracion controla cuándo expira la suscripción. El dashboard global (GET /api/admin/dashboard/overview) lista automáticamente los tenants próximos a expirar (dentro de 30 días) para que el Superadmin pueda renovarlos o contactar al cliente.


Endpoints


Creación de Tenant (Self-Service)

POST /api/auth/register-tenant

Descripción: Crea un nuevo tenant junto con su usuario administrador inicial en una sola transacción atómica. Es el punto de entrada para nuevos clientes (registro autogestionado).

Requiere Auth: No — es un endpoint público para onboarding.

Contexto de uso: Este es el primer endpoint que se llama cuando un nuevo negocio se registra en NeoPOS. Crea simultáneamente:

  • El tenant con su plan, límites y configuración inicial
  • El primer usuario con rol Administrador (1) y flag password_must_change: true
  • Los permisos por defecto para el nuevo tenant (semilla de módulos base)

Request:

CampoTipoObligatorioDescripción
tenant.codigostringCódigo único del tenant (ej: MIEMPRESA)
tenant.nombrestringNombre comercial
tenant.razon_socialstringRazón social (NIT)
tenant.nitstringNIT sin DV (ej: 900123456)
tenant.dvstringDígito de verificación (default 7)
tenant.telefonostringTeléfono de contacto
tenant.emailstringEmail corporativo
tenant.direccionstringDirección física
tenant.ciudadstringCiudad
tenant.planstringPlan: BASICO (default), PRO, PREMIUM, ENTERPRISE
tenant.limite_usuariosintMáximo usuarios (default: 3 para BASICO)
admin_nombrestringNombre del administrador
admin_correostringEmail del administrador (debe ser único en el sistema)
admin_passwordstringContraseña (mín. 8 chars, mayúscula, número, caracter especial)
{
"tenant": {
"codigo": "MIEMPRESA",
"nombre": "Mi Empresa SAS",
"razon_social": "Mi Empresa SAS",
"nit": "900123456",
"dv": "7",
"telefono": "3001234567",
"email": "info@miempresa.com",
"direccion": "Calle 123 #45-67",
"ciudad": "Bogotá",
"plan": "BASICO",
"limite_usuarios": 3
},
"admin_nombre": "Admin Principal",
"admin_correo": "admin@miempresa.com",
"admin_password": "AdminPass1!"
}

Respuesta exitosa: 201 Created

Response:

{
"tenant": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"codigo": "MIEMPRESA",
"nombre": "Mi Empresa SAS",
"estado": "ACTIVO",
"plan": "BASICO"
},
"admin": {
"id": 2,
"nombre": "Admin Principal",
"correo": "admin@miempresa.com",
"rol": 1,
"password_must_change": true
},
"mensaje": "Tenant 'Mi Empresa SAS' creado exitosamente"
}

Errores: 409 Conflict — el codigo del tenant o el admin_correo ya existen

cURL:

Terminal window
curl -X POST http://localhost/api/auth/register-tenant \
-H "Content-Type: application/json" \
-d '{
"tenant": {
"codigo": "MIEMPRESA",
"nombre": "Mi Empresa SAS",
"razon_social": "Mi Empresa SAS",
"nit": "900123456",
"email": "info@miempresa.com",
"plan": "BASICO"
},
"admin_nombre": "Admin Principal",
"admin_correo": "admin@miempresa.com",
"admin_password": "AdminPass1!"
}'

Listar Tenants

GET /api/tenants

Descripción: Lista todos los tenants del sistema con paginación. Solo Superadmin.

Requiere Auth: Sí (rol=3)
Permiso requerido: tenants, leer

Parámetros query:

ParámetroTipoObligatorioDescripción
skipintRegistros a saltar (default 0)
limitintMáximo a retornar (default 50)

Respuesta exitosa: 200 OK
Errores: 403 (no es Superadmin)

Response:

[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"codigo": "TENANT001",
"nombre": "Mi Empresa SAS",
"razon_social": "Mi Empresa SAS",
"nit": "900123456-7",
"dv": "7",
"telefono": "3001234567",
"email": "info@miempresa.com",
"direccion": "Calle 123 #45-67",
"ciudad": "Bogotá",
"estado": "ACTIVO",
"plan": "BASICO",
"limite_usuarios": 3,
"fecha_expiracion": "2027-01-01",
"fecha_creacion": "2025-01-01T00:00:00",
"fecha_actualizacion": "2025-01-15T00:00:00"
}
]

cURL:

Terminal window
curl http://localhost/api/tenants -H "Authorization: Bearer <token>"

Python:

import httpx
resp = httpx.get("http://localhost/api/tenants", headers={"Authorization": f"Bearer :token"})
tenants = resp.json()

JavaScript:

const resp = await fetch('http://localhost/api/tenants', {
headers: {'Authorization': `Bearer $:token`}
});
const tenants = await resp.json();

Obtener Tenant Actual

GET /api/tenants/current

Descripción: Obtiene la información del tenant al que pertenece el usuario autenticado. Este es el único endpoint de tenants accesible para roles que no son Superadmin (Admin y Asistente pueden consultar su propio tenant).

Requiere Auth:
Permiso requerido: No aplica (cualquier usuario autenticado)

Contexto de uso: Útil para que el frontend muestre información del negocio actual (nombre, plan, estado) en el panel de administración sin necesidad de permisos Superadmin.

Respuesta exitosa: 200 OK

Response: (misma estructura que TenantResponse)

Errores: 404 — tenant no encontrado (solo si el JWT tiene un tenant_id inválido)

cURL:

Terminal window
curl http://localhost/api/tenants/current -H "Authorization: Bearer <token>"

Obtener Tenant por ID

GET /api/tenants/:tenant_id

Descripción: Obtiene un tenant por su UUID. Superadmin (cualquier tenant) o Administrador (solo SU tenant, tenant_id del JWT == tenant_id del path).

Requiere Auth:
Permiso requerido: No consulta permisos_rol. Superadmin (rol=3) → cualquier tenant; Administrador (rol=1) → solo su propio tenant; Asistente (rol=2) u otro tenant → 403.

Parámetros de ruta:

ParámetroTipoDescripción
tenant_idstring (UUID)ID del tenant

Respuesta exitosa: 200 OK — objeto TenantResponse completo
Errores: 403 (rol no autorizado o tenant ajeno), 404 (no encontrado)

cURL:

Terminal window
curl http://localhost/api/tenants/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer <token>"

Crear Tenant (Superadmin)

POST /api/tenants

Descripción: Crea un nuevo tenant directamente. A diferencia de register-tenant, este endpoint crea solo el tenant (sin usuario administrador). Útil para migraciones, importación masiva o creación por parte del Superadmin desde el panel de control.

Requiere Auth: Sí (rol=3)
Permiso requerido: tenants, crear

Request:

CampoTipoObligatorioDescripción
codigostringCódigo único del tenant
nombrestringNombre comercial
razon_socialstringRazón social
nitstringNIT
dvstringDígito de verificación
telefonostringTeléfono
emailstringEmail corporativo
direccionstringDirección
ciudadstringCiudad
planstringPlan (default BASICO)
limite_usuariosintLímite de usuarios (default 3)
limite_terminalsintLímite de terminales POS (default 5). Controla cuántas terminales pueden registrarse/login en el tenant
estadostringEstado (default ACTIVO)
fecha_expiraciondateFecha de expiración de la suscripción
{
"codigo": "NUEVOTENANT",
"nombre": "Nueva Empresa SAS",
"razon_social": "Nueva Empresa SAS",
"nit": "900987654-3",
"telefono": "3007654321",
"email": "info@nuevaempresa.com",
"direccion": "Carrera 50 #20-30",
"ciudad": "Medellín",
"plan": "PRO",
"limite_usuarios": 10,
"estado": "ACTIVO",
"fecha_expiracion": "2027-06-30"
}

Respuesta exitosa: 201 Created — objeto TenantResponse completo
Errores: 403 (no Superadmin), 409 (código duplicado)

cURL:

Terminal window
curl -X POST http://localhost/api/tenants \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"codigo":"NUEVOTENANT","nombre":"Nueva Empresa SAS","nit":"900987654-3","plan":"PRO","limite_usuarios":10}'

Actualizar Tenant

PUT /api/tenants/:tenant_id

Descripción: Actualiza la configuración de un tenant: plan, límites, estado, datos de contacto, fecha de expiración. Solo Superadmin.

Requiere Auth: Sí (rol=3)
Permiso requerido: tenants, actualizar

Contexto de uso: Este es el endpoint principal para el control de planes y facturación:

  • Cambiar de plan (BASICOPROPREMIUM)
  • Aumentar límite de usuarios
  • Extender/suspender la cuenta (estado o fecha_expiracion)
  • Actualizar datos de contacto del negocio

Request: (todos los campos opcionales — solo enviar los que se modifican)

CampoTipoDescripción
nombrestringNombre comercial
razon_socialstringRazón social
nitstringNIT
telefonostringTeléfono
emailstringEmail corporativo
direccionstringDirección
ciudadstringCiudad
estadostringEstado: ACTIVO, INACTIVO, SUSPENDIDO, CANCELADO
planstringPlan: BASICO, PRO, PREMIUM, ENTERPRISE
limite_usuariosintMáximo de usuarios permitidos
limite_terminalsintMáximo de terminales POS del tenant
fecha_expiraciondateNueva fecha de expiración
{
"nombre": "Mi Empresa SAS Actualizado",
"plan": "PREMIUM",
"limite_usuarios": 10,
"estado": "ACTIVO",
"fecha_expiracion": "2027-12-31"
}

Respuesta exitosa: 200 OK — objeto TenantResponse completo actualizado
Errores: 403 (no Superadmin), 404 (no encontrado)

cURL:

Terminal window
curl -X PUT http://localhost/api/tenants/550e8400-e29b-41d4-a716-446655440000 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"plan":"PREMIUM","limite_usuarios":10,"fecha_expiracion":"2027-12-31"}'

Eliminar Tenant

DELETE /api/tenants/:tenant_id

Descripción: Elimina un tenant y todos sus datos asociados (usuarios, ventas, productos, etc.). Esta operación es definitiva e irreversible. Solo Superadmin.

Requiere Auth: Sí (rol=3)
Permiso requerido: tenants, eliminar

Parámetros de ruta:

ParámetroTipoDescripción
tenant_idstring (UUID)ID del tenant a eliminar

Advertencia: Esta operación elimina físicamente todos los registros del tenant (cascada por FK). No hay soft delete a nivel de tenant.

Respuesta exitosa: 200 OK

{
"mensaje": "Tenant eliminado exitosamente"
}

Errores: 403 (no Superadmin), 404 (no encontrado)

cURL:

Terminal window
curl -X DELETE http://localhost/api/tenants/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer <token>"

Monitoreo y Métricas

Métricas por Tenant

GET /api/tenants/:tenant_id/metrics

Descripción: Obtiene métricas específicas de un tenant: usuarios, ventas (hoy/mes), productos, créditos pendientes, terminales activas. Superadmin (cualquier tenant) o Administrador (solo SU tenant).

Requiere Auth:
Permiso requerido: No consulta permisos_rol. Superadmin (rol=3) → cualquier tenant; Administrador (rol=1) → solo su propio tenant; Asistente (rol=2) u otro tenant → 403.

Contexto de uso: Dashboard de administración para que el Superadmin vea el estado operativo de cada tenant sin necesidad de acceder al tenant. El Admin (rol=1) lo usa para ver su propio detalle en el panel. Útil para:

  • Monitorear actividad reciente de un cliente
  • Verificar si un tenant está usando el sistema
  • Detectar tenants inactivos o con baja operación
  • Reportes de uso por plan

Respuesta exitosa: 200 OK

{
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"nombre": "Mi Empresa SAS",
"estado": "ACTIVO",
"plan": "PRO",
"usuarios": {
"total": 8
},
"ventas": {
"hoy": 25,
"total_hoy": 1250000,
"mes": 650,
"total_mes": 32500000
},
"productos": {
"total": 150
},
"creditos": {
"pendientes": 15
},
"terminales": {
"total": 3
}
}

Campos del response:

CampoTipoDescripción
tenant_idstringUUID del tenant
nombrestringNombre comercial
estadostringEstado actual (ACTIVO, INACTIVO, etc.)
planstringPlan contratado
usuarios.totalintCantidad total de usuarios registrados
ventas.hoyintNúmero de ventas del día de hoy
ventas.total_hoyintSuma monetaria de ventas hoy
ventas.mesintNúmero de ventas del mes actual
ventas.total_mesintSuma monetaria de ventas del mes
productos.totalintTotal de productos en catálogo
creditos.pendientesintCréditos no pagados
terminales.totalintTerminales POS registradas

Errores: 403 (rol no autorizado o tenant ajeno), 404 (tenant no encontrado)

cURL:

Terminal window
curl http://localhost/api/tenants/550e8400-e29b-41d4-a716-446655440000/metrics \
-H "Authorization: Bearer <token>"

JavaScript:

const resp = await fetch('http://localhost/api/tenants/550e8400-e29b-41d4-a716-446655440000/metrics', {
headers: {'Authorization': `Bearer $:token`}
});
const metrics = await resp.json();
// metrics.ventas.hoy → 25
// metrics.usuarios.total → 8
// metrics.plan → "PRO"

Dashboard Global (Cross-Tenant)

GET /api/admin/dashboard/overview

Descripción: Visión general de todo el sistema para el Superadmin. Incluye conteo de tenants activos/inactivos, tenants próximos a expirar, total de usuarios, ventas globales del día/mes y estado del sistema (sync, cloud).

Requiere Auth: Sí (rol=3)
Permiso requerido: tenants, leer

Contexto de uso: Pantalla principal del panel Superadmin. Muestra un resumen ejecutivo del estado de toda la plataforma:

  • Tenants: Cuántos activos, inactivos y próximos a vencer
  • Usuarios: Total de usuarios en el sistema
  • Ventas globales: Hoy y en el mes (todos los tenants combinados)
  • Estado del sistema: Conectividad cloud, salud de la cola de sync, uptime

Respuesta exitosa: 200 OK

{
"tenants_activos": 5,
"tenants_inactivos": 1,
"tenants_proximos_a_expirar": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"nombre": "Mi Empresa SAS",
"fecha_expiracion": "2026-08-15",
"dias_restantes": 16
}
],
"total_usuarios": 42,
"ventas_hoy": 87,
"ventas_totales_hoy": 4350000,
"ventas_mes": 2100,
"ventas_totales_mes": 105000000,
"sync_pendiente_global": 3,
"estado_sistema": {
"cloud_connected": true,
"sync_queue_ok": true,
"uptime_horas": 720
}
}

Campos del response:

CampoTipoDescripción
tenants_activosintTenants con estado ACTIVO
tenants_inactivosintTenants con estado distinto a ACTIVO
tenants_proximos_a_expirararrayTenants activos cuya suscripción expira en ≤30 días
tenants_proximos_a_expirar[].dias_restantesintDías hasta la expiración
total_usuariosintUsuarios totales en todos los tenants
ventas_hoyintVentas totales de hoy (cross-tenant)
ventas_totales_hoyintValor monetario total de ventas hoy
ventas_mesintVentas totales del mes
ventas_totales_mesintValor monetario total del mes
sync_pendiente_globalintEventos pendientes de sincronización
estado_sistema.cloud_connectedboolConectividad con PostgreSQL
estado_sistema.sync_queue_okboolCola de sync sin acumulación (< 100)
estado_sistema.uptime_horasintHoras desde el último reinicio del API

Errores: 403 (no Superadmin)

cURL:

Terminal window
curl http://localhost/api/admin/dashboard/overview \
-H "Authorization: Bearer <token>"

JavaScript:

const resp = await fetch('http://localhost/api/admin/dashboard/overview', {
headers: {'Authorization': `Bearer $:token`}
});
const overview = await resp.json();
// overview.tenants_activos → 5
// overview.tenants_proximos_a_expirar → [{...}]

Métricas del Sistema

GET /api/system/metrics

Descripción: Métricas del servidor donde corre la API: CPU, RAM, disco, uptime, versión de Python, estado del cloud y del orquestador de sync.

Requiere Auth: Sí (rol=3)
Permiso requerido: tenants, leer

Contexto de uso: Monitoreo de infraestructura. Permite al Superadmin verificar la salud del servidor sin acceso SSH.

Respuesta exitosa: 200 OK

{
"cpu_percent": 23.5,
"memory": {
"total_bytes": 8589934592,
"used_bytes": 4294967296,
"available_bytes": 4294967296,
"percent": 50.0
},
"disk": {
"total_bytes": 107374182400,
"used_bytes": 75161927680,
"free_bytes": 32212254720,
"percent": 70.0
},
"uptime_seconds": 2592000,
"python_version": "3.12.4",
"platform": "linux",
"cloud_enabled": true,
"sync_running": true
}

Errores: 403 (no Superadmin)

cURL:

Terminal window
curl http://localhost/api/system/metrics -H "Authorization: Bearer <token>"

GET /api/system/db/metrics

Descripción: Métricas de la base de datos: tipo de BD en uso (PostgreSQL o SQLite), conteo de registros por tabla principal (ventas, productos, clientes, usuarios, tenants, créditos).

Requiere Auth: Sí (rol=3)
Permiso requerido: tenants, leer

Contexto de uso: Permite verificar el volumen de datos en cada tabla del sistema. Útil para diagnóstico de rendimiento y planificación de capacidad.

Respuesta exitosa: 200 OK

{
"database": "postgresql",
"tables": {
"ventas": 15420,
"productos": 850,
"clientes": 3200,
"usuarios": 42,
"tenants": 6,
"creditos": 450
}
}

Errores: 403 (no Superadmin)

cURL:

Terminal window
curl http://localhost/api/system/db/metrics -H "Authorization: Bearer <token>"

Resumen de Endpoints

MétodoRutaRolPermisoPropósito
POST/api/auth/register-tenantPúblicoRegistro autogestionado de nuevo tenant + admin
GET/api/tenantsSuperadmintenants, leerListar todos los tenants
GET/api/tenants/currentCualquieraInfo del tenant actual
GET/api/tenants/:idSuperadmin/Admin (solo su tenant)híbridoDetalle de un tenant
POST/api/tenantsSuperadmintenants, crearCrear tenant (sin usuario)
PUT/api/tenants/:idSuperadmintenants, actualizarActualizar plan/estado/límites
DELETE/api/tenants/:idSuperadmintenants, eliminarEliminar tenant definitivamente
GET/api/tenants/:id/metricsSuperadmin/Admin (solo su tenant)híbridoMétricas operativas del tenant
GET/api/admin/tenants/:id/activitySuperadmin/Admin (solo su tenant)híbridoActividad por usuario del tenant
GET/api/admin/dashboard/overviewSuperadmintenants, leerDashboard global cross-tenant
GET/api/system/metricsSuperadmintenants, leerMétricas del servidor (CPU/RAM/disco)
GET/api/system/db/metricsSuperadmintenants, leerMétricas de BD (conteo por tabla)