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 uses subscription-based feature gating to control which parts of the API a company can access. The active plan is stored on the Company document in the available_plans field, and it is enforced at the route level by the TokenValidationPlan middleware. Attempting to call a route that requires a higher plan than the one the company holds results in an immediate HTTP 403 response — no data is read or written.

Available Plans

MultiSas offers four plan tiers. Prices are in Colombian Pesos (COP) per month.
PlanPrice (COP/month)Key Features
Plan Básico$29,000Standard electronic invoicing (XML + PDF), client/product/supplier management, basic document storage, 1 user, 1 company, basic chat support
Plan Profesional$59,000Everything in Básico + credit & debit notes, basic inventory (stock in/out), general sales reports, multi-user access, query API, increased storage, standard support
Plan Premium$119,000Everything in Profesional + advanced inventory (kardex, cost tracking, multi-warehouse), accounts receivable, multi-company panel, full create & query API, advanced roles & permissions, expanded storage, custom PDF templates, priority support
Plan PersonalizadoCustomTailored to the customer’s specific requirements — price negotiated with the Super Admin

Feature Gates

Plan enforcement is keyed on named features defined in plan.json. Each feature maps to the list of plans that include it. The TokenValidationPlan middleware receives the feature name and checks whether the company’s current available_plans value appears in that list.
Feature keyIncluded in
facturacionPlan Basico, Plan Profesional, Plan Premium
inventario_basicoPlan Profesional, Plan Premium
inventario_avanzadoPlan Premium
multiempresaPlan Premium
The full features object from plan.json:
{
  "features": {
    "facturacion":        ["Plan Basico", "Plan Profesional", "Plan Premium"],
    "inventario_basico":  ["Plan Profesional", "Plan Premium"],
    "inventario_avanzado":["Plan Premium"],
    "multiempresa":       ["Plan Premium"]
  }
}

Plan Types

The type_available_plans field records how a plan was purchased, which determines how expiration is calculated:
ValueMeaning
MensualMonth-to-month subscription
AnualAnnual subscription — months_quantity holds the number of months purchased
VacioNo active plan type (default for new companies or after expiration)
PermanenteNon-expiring — reserved exclusively for the Super Admin account
The months_quantity field (a Number) records how many months were purchased at sign-up, and day_available_plans records the exact date and time the plan was activated.

Plan Expiration

The expired_available_plans field stores the plan’s end date as a DD/MM/YYYY string. On every authenticated request to a plan-protected route, the check_plan_expiration middleware runs before the feature gate:
  1. It reads expired_available_plans from the Company document.
  2. It parses the date and calculates how many days remain (days_left = ceil((expiredDate - today) / 86_400_000)).
  3. If days_left > 0, it sets req.user.day_available_plans to the remaining day count and calls next().
  4. If days_left <= 0, it immediately runs the following update on the Company document and then calls next() (the feature gate will then block the request):
await Company.updateOne(
  { _id: user._id },
  {
    $set: {
      available_plans: "Sin Plan",
      type_available_plans: "Vacio",
      months_quantity: 0,
      day_available_plans: "",
      expired_available_plans: "",
    },
  }
);
When a plan expires, available_plans is automatically reset to Sin Plan on the very next API request that triggers check_plan_expiration — there is no grace period. All feature-gated routes will begin returning HTTP 403 immediately. The company must contact the Super Admin to renew their plan.

Enforcing Plans in Code

The TokenValidationPlan(feature) middleware is added to any route that requires a specific plan. It reads req.user.available_plans (populated by the Token or TokenAny middleware that ran earlier in the chain) and cross-references it against plan.features[feature].
// notesRoutes.js — credit note creation requires the 'facturacion' feature
router.post(
  '/credit/:company_id/:sale_id/:production_id/:client_id',
  Token,
  TokenAuthorize('Admin', 'Super Admin'),
  TokenValidationPlan('facturacion'),
  create_credit_note
);
If the company’s plan is not in the allowed list for that feature, the middleware short-circuits the request:
// HTTP 403
{
  "msj": "Tu plan no permite usar esta funcion",
  "status": false
}
The complete middleware chain for a plan-gated, role-protected route is:
TokenAny → TokenAuthorize(...roles) → check_plan_expiration → TokenValidationPlan(feature) → controller
TokenAny must always come first so that req.user is populated before TokenAuthorize or TokenValidationPlan attempt to read it.

Build docs developers (and LLMs) love