Saltar al contenido principal

Usuarios y roles

Cada tenant tiene su propia tabla de usuarios, aislada de otros tenants.

MCP Tool: create_user

Perfil: core

Crea un usuario dentro del tenant.

Parametros

ParametroTipoRequeridoDescripcion
tenantSlugstringSiSlug del tenant
emailstringSiEmail (unico en el tenant)
passwordstringSiPassword (min 8 caracteres, se hashea)
namestringSiNombre completo
rolestringNoRol: owner, admin, member, viewer. Default: member
permissionsobjectNoPermisos por entidad
metadataobjectNoDatos adicionales (telefono, departamento, posicion, avatar)

Roles

RolDescripcion
ownerControl total. Puede gestionar todo
adminPuede gestionar usuarios y configuraciones
memberPuede crear y editar registros
viewerSolo lectura

Permisos por entidad

{
"entities": {
"productos": ["create", "read", "update", "delete"],
"facturas": ["read", "create"],
"reportes": ["read"]
},
"canManageUsers": false,
"canManageSettings": false
}

Ejemplo

create_user({
tenantSlug: "mi-empresa",
email: "vendedor@empresa.com",
password: "password123",
name: "Carlos Vendedor",
role: "member",
permissions: {
entities: {
clientes: ["create", "read", "update"],
productos: ["read"]
}
}
})

Login despues de crear

El usuario puede autenticarse via REST:

curl -X POST "https://api.fyso.dev/api/auth/tenant/login" \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: mi-empresa" \
-d '{"email":"vendedor@empresa.com","password":"password123"}'

O via MCP:

tenant_login({
tenantSlug: "mi-empresa",
email: "vendedor@empresa.com",
password: "password123"
})

MCP Tool: list_users

Perfil: core

Parametros

ParametroTipoRequeridoDescripcion
tenantSlugstringNoSlug del tenant. Default: tenant seleccionado

Ejemplo

list_users({ tenantSlug: "mi-empresa" })

Respuesta

{
"success": true,
"users": [
{
"id": "uuid",
"email": "admin@empresa.com",
"name": "Admin Principal",
"role": "owner",
"isActive": true,
"lastLogin": "2026-02-18T10:00:00Z"
}
],
"total": 2
}

Las passwords nunca se retornan.


Flujos de autogestión

Los usuarios del tenant pueden registrarse, recuperar su contraseña y cambiarla sin intervención del administrador. Estas funcionalidades están deshabilitadas por defecto y deben habilitarse explícitamente por tenant.

Feature flags

Habilita las funcionalidades de autogestión via PUT /api/auth/tenants/:id/settings:

curl -X PUT "https://api.fyso.dev/api/auth/tenants/<tenant-id>/settings" \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"selfRegistrationEnabled": true,
"passwordResetEnabled": true
}'
FlagDefaultDescripción
selfRegistrationEnabledfalsePermite que usuarios se registren solos (crea rol viewer)
passwordResetEnabledfalseHabilita el flujo de forgot-password / reset-password (requiere Resend configurado)

Todos los endpoints de autogestión son anónimos — no requieren auth de admin, solo el header X-Tenant-ID.


Autoregistro

POST /api/auth/tenant/register
X-Tenant-ID: <tenant-slug>
Content-Type: application/json

{
"name": "Jane Builder",
"email": "jane@example.com",
"password": "contraseñasegura"
}

Crea un usuario con rol viewer. Devuelve 403 si selfRegistrationEnabled es false, 409 si el email ya existe.

Respuesta (201):

{
"success": true,
"data": {
"id": "uuid",
"email": "jane@example.com",
"name": "Jane Builder",
"role": "viewer"
}
}

Recuperar contraseña

POST /api/auth/tenant/forgot-password
X-Tenant-ID: <tenant-slug>
Content-Type: application/json

{ "email": "jane@example.com" }

Envía un link de recuperación por email. Siempre devuelve 200 — la respuesta nunca revela si el email existe o no. Devuelve 403 si passwordResetEnabled es false.

Rate limit: 3 requests cada 15 minutos por IP + tenant.


Resetear contraseña

POST /api/auth/tenant/reset-password
X-Tenant-ID: <tenant-slug>
Content-Type: application/json

{
"token": "<token-del-email>",
"new_password": "nuevacontraseñasegura"
}

Aplica la nueva contraseña usando el token de un solo uso del email de recuperación. Los tokens vencen en 1 hora y se invalidan en el primer uso. Devuelve 403 si passwordResetEnabled es false.


Cambiar contraseña (autenticado)

POST /api/auth/tenant/change-password
Authorization: Bearer <user-token>
Content-Type: application/json

{
"current_password": "contraseñaactual",
"new_password": "nuevacontraseñasegura"
}

Los usuarios autenticados pueden cambiar su propia contraseña. Valida la contraseña actual antes de aplicar el cambio. Devuelve 401 si current_password es incorrecta.


Reset de contraseña por admin

PATCH /api/auth/tenant/users/:id/reset-password
Authorization: Bearer <admin-token>
Content-Type: application/json

{ "new_password": "nuevacontraseña123" }

Owner o admin puede resetear la contraseña de cualquier usuario sin conocer la contraseña actual. Requiere rol owner o admin.


MCP Tool: tenant_login

Perfil: advanced

Login como usuario del tenant. Retorna un JWT para usar con la REST API.

Parametros

ParametroTipoRequeridoDescripcion
tenantSlugstringSiSlug del tenant
emailstringSiEmail del usuario
passwordstringSiPassword

Respuesta

{
"success": true,
"token": "eyJhbGci...",
"user": {
"id": "uuid",
"email": "user@example.com",
"name": "Nombre",
"role": "member"
},
"usage": {
"header": "Authorization",
"value": "Bearer eyJhbGci...",
"note": "Use this token in the Authorization header for REST API calls"
}
}

Codigos de invitacion

Los codigos de invitacion controlan quien puede unirse a tu tenant cuando el auto-registro esta deshabilitado. Cada codigo puede ser de uso unico o multiple, con vencimiento opcional y una nota para identificarlo.

Todos los endpoints de invitaciones requieren un token de administrador autenticado en el header Authorization: Bearer <token>.

Generar una invitacion

curl -X POST https://api.fyso.dev/api/invitations \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{"note": "equipo contratista", "maxUses": 5, "expiresAt": "2026-03-31T00:00:00Z"}'

Parametros del cuerpo (todos opcionales):

ParametroTipoDescripcion
notestringEtiqueta interna para identificar el codigo
maxUsesnumberMaxima cantidad de usos. Por defecto: 1
expiresAtstringFecha de vencimiento en formato ISO 8601

Respuesta:

{
"success": true,
"data": {
"token": "FYSO-A3B4-C5D6",
"inviteUrl": "https://app.example.com/invite/FYSO-A3B4-C5D6"
}
}

Comparte el inviteUrl directamente con el invitado, o usa el token en un flujo de onboarding personalizado.

Listar todas las invitaciones

curl https://api.fyso.dev/api/invitations \
-H "Authorization: Bearer <admin-token>"

Devuelve todos los codigos de invitacion del tenant, incluyendo contadores de uso y estado.

Invalidar una invitacion

curl -X DELETE https://api.fyso.dev/api/invitations/FYSO-A3B4-C5D6 \
-H "Authorization: Bearer <admin-token>"

Desactiva el codigo (is_active = false). Cualquier intento posterior de uso devuelve un error. Retorna 404 si el token no se encuentra.

Validar un codigo (publico)

curl -X POST https://api.fyso.dev/api/invitations/validate \
-H "Content-Type: application/json" \
-d '{"code": "FYSO-A3B4-C5D6"}'

No requiere autenticacion. Retorna { "valid": true } si el codigo esta activo, no vencido y tiene usos disponibles.


Invitaciones de miembros del tenant

Las invitaciones de miembros permiten invitar a personas especificas a unirse a un tenant mediante un link de un solo uso. A diferencia de los codigos de invitacion (que controlan el registro en la plataforma), estas invitaciones crean un camino de onboarding directo a un tenant existente.

Todos los endpoints requieren un token de administrador autenticado en Authorization: Bearer <admin-token> y el header X-Tenant-Slug: <slug> para identificar el tenant.

Crear una invitacion

curl -X POST https://api.fyso.dev/api/invitations \
-H "Authorization: Bearer <admin-token>" \
-H "X-Tenant-Slug: mi-tenant" \
-H "Content-Type: application/json" \
-d '{"email": "colega@empresa.com", "expiresInDays": 7}'

Parametros del cuerpo (todos opcionales):

ParametroTipoDescripcion
emailstringLimita la invitacion a este email. El invitado debe registrarse con esta direccion exacta.
expiresInDaysnumberDias hasta que vence la invitacion. Por defecto: 7

Respuesta (201):

{
"success": true,
"data": {
"token": "a3f1b2c4...hex64",
"inviteUrl": "https://app.fyso.dev/invite/a3f1b2c4...hex64"
}
}

Comparte el inviteUrl con el invitado. El link es valido hasta que se acepte o venza. Cada invitacion es de un solo uso.

Listar invitaciones

curl https://api.fyso.dev/api/invitations \
-H "Authorization: Bearer <admin-token>" \
-H "X-Tenant-Slug: mi-tenant"

Devuelve todas las invitaciones del tenant ordenadas por fecha de creacion. Las invitaciones pendientes con fecha vencida se marcan automaticamente como expired al recuperarlas.

Respuesta:

{
"success": true,
"data": [
{
"id": "uuid",
"token": "a3f1b2c4...hex64",
"email": "colega@empresa.com",
"status": "pending",
"accepted_at": null,
"expires_at": "2026-03-02T12:00:00Z",
"created_at": "2026-02-23T12:00:00Z",
"invited_by_name": "Admin Principal",
"invited_by_email": "admin@mi-tenant.com"
}
]
}

Valores de estado:

EstadoDescripcion
pendingInvitacion enviada, aun no aceptada
acceptedEl invitado se registro exitosamente
expiredVencio sin ser aceptada
revokedCancelada manualmente por un admin

Revocar una invitacion

curl -X DELETE https://api.fyso.dev/api/invitations/<token> \
-H "Authorization: Bearer <admin-token>" \
-H "X-Tenant-Slug: mi-tenant"

Cambia el estado de la invitacion a revoked. Solo se pueden revocar invitaciones en estado pending. Retorna 404 si el token no se encuentra o ya fue usado o vencido.

Previsualizar una invitacion (publico)

curl https://api.fyso.dev/auth/invite/<token>

No requiere autenticacion. Devuelve los detalles de la invitacion para que el frontend pueda mostrar una vista previa antes de que el usuario se registre.

Respuesta:

{
"success": true,
"data": {
"valid": true,
"email": "colega@empresa.com",
"tenantSlug": "mi-tenant"
}
}

Retorna 400 con un mensaje de error si la invitacion es invalida, vencida, aceptada o revocada.

Aceptar una invitacion

curl -X POST https://api.fyso.dev/auth/invite/accept \
-H "Content-Type: application/json" \
-d '{
"token": "<token-de-invitacion>",
"email": "colega@empresa.com",
"name": "Juan Perez",
"password": "contraseñasegura"
}'

No requiere autenticacion previa. El token de invitacion actua como acceso.

Parametros del cuerpo:

ParametroTipoRequeridoDescripcion
tokenstringSiToken de invitacion del link recibido
emailstringSiEmail del registro. Debe coincidir con el email de la invitacion si se especifico uno
namestringSiNombre completo (minimo 1 caracter sin espacios)
passwordstringSiContrasena (minimo 8 caracteres)

Respuesta (201):

{
"success": true,
"data": {
"id": "uuid",
"email": "colega@empresa.com",
"name": "Juan Perez",
"role": "member"
}
}

La invitacion se reclama de forma atomica — solicitudes concurrentes no pueden reclamar el mismo token dos veces. Retorna 409 si el email ya existe en el tenant, 403 si el email no coincide con la invitacion, y 403 si el token es invalido, vencido o revocado.