Gestión de Inquilinos

Cree, liste, recupere y actualice inquilinos en la plataforma mindzieStudio.

IMPORTANTE: Todos los endpoints en esta página requieren una Clave API Global. Las claves API específicas de inquilinos recibirán un error 401 No autorizado.


Listar Todos los Inquilinos

GET /api/tenant

Recupera una lista paginada de todos los inquilinos en el sistema con estadísticas resumidas.

Parámetros de Consulta

Parámetro Tipo Predeterminado Descripción
page entero 1 Número de página para paginación
pageSize entero 50 Número de elementos por página (máx.: 100)

Respuesta (200 OK)

{
  "tenants": [
    {
      "tenantId": "12345678-1234-1234-1234-123456789012",
      "name": "acme-corp",
      "displayName": "Acme Corporation",
      "description": "Inquilino principal para Acme Corporation",
      "caseCount": 50000,
      "maxUserCount": 100,
      "maxAnalystCount": 20,
      "analystCount": 12,
      "userCount": 45,
      "preRelease": false,
      "isAcademic": false,
      "autoload": true,
      "dateCreated": "2024-01-15T10:30:00Z",
      "isDisabled": false
    }
  ],
  "totalCount": 5,
  "page": 1,
  "pageSize": 50
}

Campos del Objeto Inquilino

Campo Tipo Descripción
tenantId GUID Identificador único para el inquilino
name string Nombre único en el sistema (usado en URLs)
displayName string Nombre para mostrar legible por humanos
description string Descripción del inquilino
caseCount entero Número total de casos en todos los conjuntos de datos
maxUserCount entero Número máximo permitido de usuarios
maxAnalystCount entero Número máximo permitido de analistas
analystCount entero Número actual de analistas
userCount entero Número actual de usuarios
preRelease booleano Si el inquilino tiene características previas al lanzamiento
isAcademic booleano Si este es un inquilino académico
autoload booleano Si se cargan proyectos automáticamente
dateCreated datetime Fecha de creación del inquilino
isDisabled booleano Si el inquilino está deshabilitado

Respuestas de Error

No autorizado (401):

{
  "error": "Este endpoint requiere una clave API Global. Las claves API específicas de inquilinos no pueden listar todos los inquilinos.",
  "hint": "Las claves API Globales pueden crearse en /admin/global-api-keys"
}

Obtener Inquilino por ID

GET /api/tenant/{tenantId}

Recupera información detallada para un inquilino específico por su ID.

Parámetros de Ruta

Parámetro Tipo Requerido Descripción
tenantId GUID Identificador único del inquilino

Respuesta (200 OK)

{
  "tenantId": "12345678-1234-1234-1234-123456789012",
  "name": "acme-corp",
  "displayName": "Acme Corporation",
  "description": "Inquilino principal para Acme Corporation",
  "isAcademic": false,
  "preRelease": false,
  "maxUserCount": 100,
  "maxAnalystCount": 20,
  "maxCases": 100000,
  "dateCreated": "2024-01-15T10:30:00Z",
  "isDisabled": false
}

Respuestas de Error

No encontrado (404):

{
  "error": "Inquilino con ID '12345678-1234-1234-1234-123456789012' no encontrado"
}

Crear Inquilino

POST /api/tenant

Crea un nuevo inquilino en el sistema con toda la infraestructura necesaria.

Cuerpo de la Solicitud

{
  "name": "new-tenant",
  "displayName": "New Tenant Corp",
  "description": "Descripción del nuevo inquilino",
  "maxUsers": 50,
  "maxAnalyst": 10,
  "maxCases": 100000,
  "timeZone": "America/New_York"
}

Campos de la Solicitud

Campo Tipo Requerido Descripción
name string Nombre único en el sistema (3-63 caracteres, alfanumérico en minúsculas con guiones)
displayName string Nombre para mostrar legible por humanos
description string No Descripción del inquilino
maxUsers entero Número máximo de usuarios
maxAnalyst entero Número máximo de analistas
maxCases entero Número máximo de casos
timeZone string No Zona horaria para el inquilino

Requisitos para el Nombre del Inquilino

  • 3-63 caracteres
  • Alfanumérico en minúsculas con guiones solamente
  • Sin espacios ni caracteres especiales
  • Debe ser único entre todos los inquilinos

Respuesta (201 Creado)

{
  "tenantId": "aabbccdd-1234-1234-1234-123456789012",
  "name": "new-tenant",
  "displayName": "New Tenant Corp",
  "message": "Inquilino 'New Tenant Corp' creado con éxito",
  "storageContainerCreated": true
}

Respuestas de Error

Conflicto (409):

{
  "error": "Ya existe un inquilino con el nombre 'new-tenant'"
}

Límite de Licencia (429):

{
  "error": "Se alcanzó el número máximo de inquilinos. Su licencia permite 10 inquilinos.",
  "hint": "Actualice su licencia para crear más inquilinos"
}

Error de Validación (400):

{
  "error": "Validación fallida",
  "validationErrors": [
    "El nombre debe tener entre 3 y 63 caracteres",
    "El nombre solo puede contener letras minúsculas, números y guiones"
  ]
}

Actualizar Inquilino

PUT /api/tenant

Actualiza las propiedades de un inquilino existente. Solo los campos proporcionados serán actualizados; los valores nulos son ignorados.

Cuerpo de la Solicitud

{
  "tenantId": "12345678-1234-1234-1234-123456789012",
  "displayName": "Acme Corporation Actualizado",
  "description": "Descripción actualizada",
  "maxUsers": 100,
  "maxAnalyst": 25,
  "maxCases": 200000,
  "timeZone": "America/New_York",
  "isAcademic": false,
  "preRelease": true,
  "isDisabled": false
}

Campos de la Solicitud

Campo Tipo Requerido Descripción
tenantId GUID Inquilino a actualizar
displayName string No Nuevo nombre para mostrar (null = sin cambios)
description string No Nueva descripción (null = sin cambios, "" = borrar)
maxUsers entero No Máximo de usuarios (null = sin cambios)
maxAnalyst entero No Máximo de analistas (null = sin cambios)
maxCases entero No Máximo de casos (null = sin cambios, -1 = ilimitado)
timeZone string No ID de zona horaria (null = sin cambios)
isAcademic booleano No Indicador académico (null = sin cambios)
preRelease booleano No Características previas al lanzamiento (null = sin cambios)
isDisabled booleano No Deshabilitar inquilino (null = sin cambios)

Nota: El name del inquilino no puede cambiarse después de la creación.

Respuesta (200 OK)

{
  "tenantId": "12345678-1234-1234-1234-123456789012",
  "name": "acme-corp",
  "displayName": "Acme Corporation Actualizado",
  "message": "Inquilino 'acme-corp' actualizado con éxito",
  "isDisabled": false
}

Respuestas de Error

No encontrado (404):

{
  "error": "Inquilino con ID '12345678-1234-1234-1234-123456789012' no encontrado"
}

Error de Validación (400):

{
  "error": "Validación fallida",
  "validationErrors": ["El nombre para mostrar no puede exceder los 255 caracteres"]
}

Ejemplos de Implementación

cURL

# Listar todos los inquilinos
curl -X GET "https://your-mindzie-instance.com/api/tenant?page=1&pageSize=50" \
  -H "Authorization: Bearer YOUR_GLOBAL_API_KEY"

# Obtener inquilino específico por ID
curl -X GET "https://your-mindzie-instance.com/api/tenant/12345678-1234-1234-1234-123456789012" \
  -H "Authorization: Bearer YOUR_GLOBAL_API_KEY"

# Crear inquilino
curl -X POST "https://your-mindzie-instance.com/api/tenant" \
  -H "Authorization: Bearer YOUR_GLOBAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "new-tenant",
    "displayName": "New Tenant Corp",
    "description": "Test tenant",
    "maxUsers": 50,
    "maxAnalyst": 10,
    "maxCases": 100000
  }'

# Actualizar inquilino
curl -X PUT "https://your-mindzie-instance.com/api/tenant" \
  -H "Authorization: Bearer YOUR_GLOBAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "12345678-1234-1234-1234-123456789012",
    "displayName": "New Tenant Corp Updated",
    "maxUsers": 100,
    "isDisabled": false
  }'

Python

import requests

BASE_URL = 'https://your-mindzie-instance.com'

class TenantManager:
    def __init__(self, global_api_key):
        """Inicializa con una clave API GLOBAL (no específica de inquilino)."""
        self.headers = {
            'Authorization': f'Bearer {global_api_key}',
            'Content-Type': 'application/json'
        }

    def list_tenants(self, page=1, page_size=50):
        """Lista todos los inquilinos en el sistema."""
        url = f'{BASE_URL}/api/tenant'
        params = {'page': page, 'pageSize': page_size}
        response = requests.get(url, headers=self.headers, params=params)
        response.raise_for_status()
        return response.json()

    def get_tenant(self, tenant_id):
        """Obtiene un inquilino específico por ID."""
        url = f'{BASE_URL}/api/tenant/{tenant_id}'
        response = requests.get(url, headers=self.headers)
        response.raise_for_status()
        return response.json()

    def create_tenant(self, name, display_name, description='', max_users=50,
                      max_analyst=10, max_cases=100000, timezone=None):
        """Crea un nuevo inquilino."""
        url = f'{BASE_URL}/api/tenant'
        payload = {
            'name': name,
            'displayName': display_name,
            'description': description,
            'maxUsers': max_users,
            'maxAnalyst': max_analyst,
            'maxCases': max_cases
        }
        if timezone:
            payload['timeZone'] = timezone

        response = requests.post(url, json=payload, headers=self.headers)
        response.raise_for_status()
        return response.json()

    def update_tenant(self, tenant_id, display_name=None, description=None,
                      max_users=None, max_analyst=None, is_disabled=None):
        """Actualiza un inquilino existente."""
        url = f'{BASE_URL}/api/tenant'
        payload = {'tenantId': tenant_id}
        if display_name is not None:
            payload['displayName'] = display_name
        if description is not None:
            payload['description'] = description
        if max_users is not None:
            payload['maxUsers'] = max_users
        if max_analyst is not None:
            payload['maxAnalyst'] = max_analyst
        if is_disabled is not None:
            payload['isDisabled'] = is_disabled

        response = requests.put(url, json=payload, headers=self.headers)
        response.raise_for_status()
        return response.json()

# Uso
manager = TenantManager('your-global-api-key')

# Listar todos los inquilinos
result = manager.list_tenants()
print(f"Total de inquilinos: {result['totalCount']}")
for tenant in result['tenants']:
    print(f"- {tenant['displayName']} ({tenant['name']})")
    print(f"  Usuarios: {tenant['userCount']}/{tenant['maxUserCount']}")

# Crear un nuevo inquilino
new_tenant = manager.create_tenant(
    name='test-tenant',
    display_name='Test Tenant',
    description='Creado vía API',
    max_users=25,
    max_analyst=5,
    max_cases=50000
)
print(f"Inquilino creado: {new_tenant['tenantId']}")

# Actualizar límites del inquilino
manager.update_tenant(
    tenant_id=new_tenant['tenantId'],
    max_users=50,
    max_analyst=10
)
print("Límites del inquilino actualizados")

JavaScript

const BASE_URL = 'https://your-mindzie-instance.com';

class TenantManager {
  constructor(globalApiKey) {
    this.headers = {
      'Authorization': `Bearer ${globalApiKey}`,
      'Content-Type': 'application/json'
    };
  }

  async listTenants(page = 1, pageSize = 50) {
    const url = `${BASE_URL}/api/tenant?page=${page}&pageSize=${pageSize}`;
    const response = await fetch(url, { headers: this.headers });
    if (!response.ok) throw new Error(`Falló: ${response.status}`);
    return await response.json();
  }

  async getTenant(tenantId) {
    const url = `${BASE_URL}/api/tenant/${tenantId}`;
    const response = await fetch(url, { headers: this.headers });
    if (!response.ok) throw new Error(`Falló: ${response.status}`);
    return await response.json();
  }

  async createTenant(config) {
    const url = `${BASE_URL}/api/tenant`;
    const response = await fetch(url, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify(config)
    });
    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.error || `Falló: ${response.status}`);
    }
    return await response.json();
  }

  async updateTenant(tenantId, updates) {
    const url = `${BASE_URL}/api/tenant`;
    const response = await fetch(url, {
      method: 'PUT',
      headers: this.headers,
      body: JSON.stringify({ tenantId, ...updates })
    });
    if (!response.ok) throw new Error(`Falló: ${response.status}`);
    return await response.json();
  }
}

// Uso
const manager = new TenantManager('your-global-api-key');

// Listar inquilinos
const tenants = await manager.listTenants();
console.log(`Encontrados ${tenants.totalCount} inquilinos`);

// Crear inquilino
const newTenant = await manager.createTenant({
  name: 'new-tenant',
  displayName: 'Nuevo Inquilino',
  maxUsers: 50,
  maxAnalyst: 10,
  maxCases: 100000
});
console.log(`Creado: ${newTenant.tenantId}`);

// Actualizar inquilino
await manager.updateTenant(newTenant.tenantId, {
  displayName: 'Nombre de Inquilino Actualizado',
  maxUsers: 100
});

Mejores Prácticas

  1. Claves API Globales: Use solo claves API globales para la gestión de inquilinos, ya que tienen privilegios significativos a nivel de sistema
  2. Conciencia de Licencias: Controle la cantidad de inquilinos frente a los límites de licencia antes de crear nuevos inquilinos
  3. Planificación de Capacidad: Establezca límites adecuados de usuarios y analistas según el uso esperado
  4. Convenciones de Nombres: Use nombres consistentes, en minúsculas y con guiones para los nombres de inquilinos