Skip to content

Subscription Plans

Feature Basic Pro Clínica Trial Forever Free
Doctors 2 8 Unlimited 8 Unlimited
Staff users 1 1 Unlimited 1 Unlimited
WhatsApp chatbot
Analytics dashboard
Patient CSV export
Patient CSV import
Quick user switching
ICS calendar feeds
Appointment reminders
Daily agenda

Temporary access for evaluation. Expires after a set number of days (configured per invite code). Same features as Pro. Converts to a paid plan via the Billing page.

Entry-level paid plan. Ideal for solo practitioners. Limited to 2 doctors and 1 staff user.

Mid-tier plan. Up to 8 doctors, analytics, and patient import/export. Best for growing clinics.

Top-tier plan. Unlimited doctors and staff users. Designed for multi-doctor clinics with reception teams.

Superadmin-granted plan with permanent access and unlimited features. Used for partner clinics, demos, and beta customers. Cannot be purchased — only granted via the superadmin API.


Plan limits are enforced server-side in Express middleware:

  • Doctor limit: checkDoctorLimit middleware on POST /api/doctors
  • User limit: checkUserLimit middleware on POST /api/users
  • Feature gates: requirePlan('pro', 'clinica', 'trial') middleware on analytics and import/export endpoints

The middleware checks the live database on every request — changing a clinic’s plan takes effect immediately without requiring a new JWT.


  1. Clinic staff visits the Suscripción (Billing) page in the dashboard
  2. Clicks the plan they want → redirected to LemonSqueezy checkout (VITE_LS_URL_* env vars)
  3. Completes payment on LemonSqueezy
  4. LemonSqueezy sends order_created webhook to POST /webhooks/lemonsqueezy
  5. Webhook handler validates signature, matches variant_id to plan, updates clinic’s subscription_plan in the database
  6. Next API request with the old JWT will get the updated plan (live DB check)

All paid plans (Basic, Pro, Clínica) have a subscription_expires_at date. On every API request, requireActiveSubscription checks:

if subscription_plan !== 'forever_free' && subscription_expires_at < now():
return 402 Subscription Expired

When expired, staff can still log in but all protected API calls return 402. They must renew via the Billing page.

Trial plans work the same way — they expire on the date set when the invite code was generated.


To manually change a clinic’s plan:

Terminal window
curl -X PATCH https://api.clinicflow.lat/api/superadmin/clinics/{clinicId} \
-H "X-Admin-Key: {SUPER_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{"plan": "pro", "expiresInDays": 365}'

See Superadmin Operations Guide for more.