Documentation Index
Fetch the complete documentation index at: https://mintlify.com/fredy-rizo/MultiSas/llms.txt
Use this file to discover all available pages before exploring further.
MultiSas secures every protected route with JSON Web Tokens (JWT) signed using the SECRET environment variable and the jsonwebtoken library. When a company or sub-user logs in, the API mints a token that encodes the caller’s identity and role. Clients must include that token on every subsequent request. There is no session storage on the server — the token is the complete proof of identity.
Never commit your SECRET to version control. Use a long (32+ character), cryptographically random value in production — e.g., openssl rand -base64 32 — and store it in your hosting platform’s secret management system or a .env file that is listed in .gitignore.
All authenticated requests must include the following HTTP header:
token-access: Bearer <your_jwt_token>
The middleware in src/core/middleware/tools/Token.js reads this header and splits it to extract the raw token:
const authHeader = req.headers["token-access"];
const token = authHeader?.split(" ")[1];
If the header is absent, the API returns immediately with HTTP 401:
{ "msj": "Sin autorizacion", "status": false }
Company Authentication
These are the two public endpoints for company-level (tenant admin) authentication. Neither requires a token.
Register a new company
POST /api/user/register-company
Creates a new tenant. The type_company field initialises the company’s bill counters for its vertical. Omit it only when creating a Super Admin account.
Request body:
{
"name_company": "Acme Corp",
"name_founder": "John Doe",
"nit_company": "900123456",
"password": "securepassword",
"type_company": "sublimacion"
}
| Field | Required | Description |
|---|
name_company | ✅ | Legal name of the company. |
name_founder | ✅ | Full name of the company founder / account owner. |
nit_company | ✅ | Unique tax ID (NIT/RUT). Used as the login identifier. |
password | ✅ | Plaintext password — hashed with bcrypt (6 salt rounds) before storage. |
type_company | ✅ (for tenants) | Business vertical: sublimacion, restaurante, farmacia, etc. |
The new company is created with active_account: [{ name: "Pendiente", value: "1" }] and available_plans: "Sin Plan". A Super Admin must call PUT /api/user/update-company/:company_id to activate the account and assign a plan.
Log in as a company admin
POST /api/user/login-company
Authenticates against the stored bcrypt hash, issues a JWT signed with the SECRET, persists the token on the Company document, and returns it in the response body.
Request body:
{
"nit_company": "900123456",
"password": "securepassword"
}
cURL example:
curl -s -X POST http://localhost:3000/api/user/login-company \
-H "Content-Type: application/json" \
-d '{"nit_company": "900123456", "password": "securepassword"}'
Response:
{
"msj": "Bienvenido!",
"status": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NjRmMWEyYjNjNGQ1ZTZmN2E4YjljMGQiLCJuYW1lX2NvbXBhbnkiOiJBY21lIENvcnAiLCJyb2xlX3VzZXIiOiJBZG1pbiIsImlhdCI6MTcxNjAwMDAwMCwiZXhwIjoxNzQ3NTM2MDAwfQ.signature",
"user": {
"_id": "664f1a2b3c4d5e6f7a8b9c0d",
"name_company": "Acme Corp",
"name_founder": "John Doe",
"nit_company": "900123456",
"role_user": "Admin",
"available_plans": "Plan Profesional",
"active_account": [{ "name": "Activo", "value": "2" }],
"day_available_plans": "1/5/2025",
"expired_available_plans": "1/6/2025"
}
}
Store the value of "token" on the client and pass it in the token-access header for every subsequent request.
Sub-User Authentication
Company admins can create employee or seller accounts that log in with their own credentials and operate within the company’s scope.
Step 1 — Admin creates a sub-user
POST /api/user/create-user-company-by-admin/:company_id
Requires a valid company-admin or Super Admin token. The new sub-user is created in an inactive state (active: false); the admin must separately activate the account.
Request headers:
token-access: Bearer <company_admin_token>
Request body:
{
"email_user_company": "seller@acmecorp.com",
"name_user_company": "Jane Smith",
"role_user_company": "Vendedor",
"password_user_company": "sellerpassword"
}
Step 2 — Admin activates the sub-user
PUT /api/user/active-account-user-by-company/:user_company_id
Step 3 — Sub-user logs in
POST /api/user/login-user-company
Sub-users authenticate with their company’s nit_company and their own password.
Request body:
{
"nit_company_by_user": "900123456",
"password_user_company": "sellerpassword"
}
Response:
{
"msj": "Iniciando sesion...",
"status": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"data": {
"company": "664f1a2b3c4d5e6f7a8b9c0d",
"email_user_company": "seller@acmecorp.com",
"name_user_company": "Jane Smith",
"role_user_company": "Vendedor",
"nit_company_by_user": "900123456",
"active": true
}
}
The returned token is a sub-user JWT. Routes protected by TokenUserCompany will accept it; routes protected by Token (company-admin-only) will not. Use TokenAny routes when both principals need access.
Token Types & Middleware
MultiSas provides five composable middleware functions that can be stacked on any route:
| Middleware | Validates | Used For |
|---|
Token | Company JWT (Company collection) | Company-admin-only routes |
TokenUserCompany | Sub-user JWT (UserCompany collection) | Sub-user-only routes |
TokenAny | Either a company or sub-user JWT | Mixed-access routes (checks Company first, then UserCompany) |
TokenAuthorize(...roles) | Role field on the resolved identity | Restricts a route to one or more named roles |
TokenValidationPlan(feature) | available_plans vs. plan.json feature map | Feature-gated routes that require a minimum subscription plan |
Example — route requiring any authenticated user with Admin or Super Admin role:
router.get(
"/list-user-by-company-active/:company_id/:pag?/:perpage?",
TokenAny,
TokenAuthorize("Admin", "Super Admin"),
Paginate,
list_user_by_company_active
);
Example — route gating a feature by subscription plan:
router.get(
"/advanced-inventory",
Token,
TokenValidationPlan("inventario_avanzado"),
getAdvancedInventory
);
TokenAuthorize must always be preceded by TokenAny, Token, or TokenUserCompany because it reads req.user, which those middlewares populate.
Roles
Each identity in MultiSas carries a role field that TokenAuthorize uses to allow or deny access.
Company roles (role_user on the Company model)
| Role | Description |
|---|
Super Admin | Platform-level administrator. Can register companies, assign plans, and access all tenants. Created by omitting type_company during registration. |
Admin | Tenant administrator. Manages their own company’s sub-users, views reports, and configures settings. Assigned by the Super Admin when a plan is activated. |
Vendedor | Seller / point-of-sale operator. Has access to sales and order creation but cannot manage users or settings. |
Sin rol | Default role assigned at registration before the Super Admin activates the account. Has no elevated permissions. |
Sub-user roles (role_user_company on the UserCompany model)
Sub-users have their own role enum — Vendedor, Consultor, Diseñador, and Sin rol — stored in the role_user_company field and validated against the UserCompany collection by TokenUserCompany and TokenAny. The TokenAuthorize middleware handles both principal types transparently by checking req.user.type_dato ("company" or "user_company").
Token Expiry
Tokens are signed with expiresIn: "365d" (one year). When a token expires, any request using it will receive:
{ "msj": "Sesion finalizada", "status": false }
with HTTP status 403. The client must discard the expired token and re-authenticate by calling the appropriate login endpoint (/api/user/login-company or /api/user/login-user-company) to obtain a fresh token.
Any other JWT verification error (e.g., tampered signature, wrong secret) returns:
{ "msj": "<error message>. Rechazo en la conexion", "status": false }
also with HTTP 403.