Skip to main content

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.

Token Header Format

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"
}
FieldRequiredDescription
name_companyLegal name of the company.
name_founderFull name of the company founder / account owner.
nit_companyUnique tax ID (NIT/RUT). Used as the login identifier.
passwordPlaintext 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
{ "active": true }

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:
MiddlewareValidatesUsed For
TokenCompany JWT (Company collection)Company-admin-only routes
TokenUserCompanySub-user JWT (UserCompany collection)Sub-user-only routes
TokenAnyEither a company or sub-user JWTMixed-access routes (checks Company first, then UserCompany)
TokenAuthorize(...roles)Role field on the resolved identityRestricts a route to one or more named roles
TokenValidationPlan(feature)available_plans vs. plan.json feature mapFeature-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)

RoleDescription
Super AdminPlatform-level administrator. Can register companies, assign plans, and access all tenants. Created by omitting type_company during registration.
AdminTenant administrator. Manages their own company’s sub-users, views reports, and configures settings. Assigned by the Super Admin when a plan is activated.
VendedorSeller / point-of-sale operator. Has access to sales and order creation but cannot manage users or settings.
Sin rolDefault 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.

Build docs developers (and LLMs) love