Skip to main content
Mesa de Ayuda uses four fixed roles to control what each user can see and do. The role is stored in the user record and embedded in every JWT token issued at login.

The four roles

ADMIN

Full access to all tickets and all operations across every area. Manages users, configuration, and system-wide data.

MESA

Help-desk agents. Full access to all tickets. Can assign, transfer, reclassify, and reopen tickets across all areas.

AREA

Department staff. Can view and act on tickets only within their own area. Cannot assign, transfer, reclassify, or reopen tickets.

USUARIO

The ticket requester. No account or authentication required. Interacts only through the public endpoints (/crear and /consultar).
USUARIO is not a JWT role — it represents unauthenticated requesters who submit and track tickets without logging in.

Permissions matrix

The table below maps every ticket endpoint to the roles that can call it.
EndpointADMINMESAAREAUSUARIO
POST /tickets/crear
POST /tickets/consultar
GET /tickets/dashboard
GET /tickets/dashboard-metricas
GET /tickets/{ticket_id}
POST /tickets/{ticket_id}/actualizar
POST /tickets/{ticket_id}/pausar
POST /tickets/{ticket_id}/cancelar
POST /tickets/{ticket_id}/archivar
POST /tickets/{ticket_id}/asignar
POST /tickets/{ticket_id}/transferir
POST /tickets/{ticket_id}/reclasificar
POST /tickets/{ticket_id}/reabrir
Dashboard and metrics endpoints return filtered data. AREA users see only tickets from their area; ADMIN and MESA see all tickets.

Area-based scoping for the AREA role

When a user with the AREA role accesses a specific ticket, the API compares the ticket’s assigned area against the user’s area. If they do not match, the request is rejected with 403 No autorizado para acceder a este ticket.
def _validate_ticket_access(ticket: dict, user: dict) -> None:
    rol = _normalize(user.get("rol"))
    if rol in ("ADMIN", "MESA"):
        return  # Full access — no area check
    if rol == "AREA":
        ticket_area = _ticket_area_name(ticket)
        user_area   = _user_area_name(user)
        if ticket_area != user_area:
            raise HTTPException(status_code=403, detail="No autorizado para acceder a este ticket")
        return
    raise HTTPException(status_code=403, detail="No autorizado")
This scoping applies to:
  • Fetching a single ticket (GET /tickets/{ticket_id})
  • Updating, pausing, cancelling, and archiving a ticket
  • Dashboard and metrics views (rows are filtered server-side)
An AREA user who attempts to access a ticket belonging to a different area receives a 403 even if they know the ticket ID.

Role in the JWT token

After a successful login, the API issues a JWT whose payload includes the user’s role and area:
{
  "sub": "user-uuid",
  "email": "agente@empresa.com",
  "nombre": "Ana García",
  "rol": "AREA",
  "area": "Sistemas",
  "exp": 1711234567
}
Every protected endpoint reads the rol claim through the require_roles dependency:
def require_roles(*allowed_roles: str):
    def _dep(user: dict = Depends(get_current_user)):
        rol = user.get("rol")
        if rol not in allowed_roles:
            raise HTTPException(status_code=403, detail="No autorizado")
        return user
    return _dep
Pass the JWT in the Authorization header of every authenticated request:
Authorization: Bearer <token>

Managing users

User accounts are created with a rol field that must be one of the four valid values:
Role = Literal["ADMIN", "MESA", "AREA", "USUARIO"]
When creating or updating a user, supply the area field for any user with the AREA role — this value is what the server uses for area-based ticket scoping.
{
  "email": "soporte@empresa.com",
  "nombre": "Carlos López",
  "password": "secure123",
  "rol": "AREA",
  "area": "Recursos Humanos"
}

Build docs developers (and LLMs) love