Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/JuanSebasSV/healtyhelp/llms.txt

Use this file to discover all available pages before exploring further.

Auth API

Base path: /api/auth All protected endpoints require an Authorization: Bearer <token> header. Tokens are signed JWTs issued on login, registration verification, and OAuth callbacks.

Authentication & Authorization

The protect middleware validates the JWT from the Authorization header. If the token is missing, expired, or invalid the request is rejected before reaching the route handler.
ConditionStatusError
No Authorization header401"No autorizado - Token no proporcionado"
Token expired / invalid signature401"Token inválido o expirado"
User deleted after token issue401"Usuario no existe o fue eliminado"

The User Object

All authenticated endpoints that return user data include the following shape:
{
  "id": "64a1f2c3d4e5f6a7b8c9d0e1",
  "name": "María García",
  "email": "maria@example.com",
  "role": "user",
  "avatar": "https://res.cloudinary.com/demo/image/upload/v1/avatars/abc123.jpg",
  "googleId": null,
  "isVerified": true,
  "hasPassword": true,
  "isSuperAdmin": false,
  "birthDate": "1995-06-15T00:00:00.000Z",
  "age": 29,
  "weight": 65.5,
  "height": 168,
  "alergia": "lactosa",
  "termsAccepted": true,
  "termsVersion": "1.2.0",
  "profileComplete": true,
  "activeTermsVersion": "1.2.0",
  "autoLogoutEnabled": false,
  "autoLogoutMinutes": 15,
  "createdAt": "2024-01-10T12:00:00.000Z"
}
FieldTypeDescription
idstringMongoDB ObjectId
namestringDisplay name
emailstringUnique email address
rolestring"user" or "admin"
avatarstring | nullCloudinary URL or null
googleIdstring | nullGoogle OAuth sub, or null for email accounts
isVerifiedbooleanEmail has been confirmed
hasPasswordbooleanAccount has a local password (may be absent on some responses)
isSuperAdminbooleanSuper-administrator flag
birthDatestring | nullISO 8601 date
agenumber | nullComputed from birthDate
weightnumber | nullIn kilograms
heightnumber | nullIn centimeters
alergiastringFree-text allergy description
termsAcceptedbooleanHas accepted current terms
termsVersionstringVersion of terms accepted
profileCompletebooleantrue when age ≥ 18, weight 40–300 kg, height 50–210 cm are all set
activeTermsVersionstringLatest published terms version (returned by /me)
autoLogoutEnabledbooleanAuto-logout preference
autoLogoutMinutesnumberIdle timeout in minutes (1–480)
createdAtstringISO 8601 timestamp

POST /api/auth/register

Creates a new user account and sends a 6-digit email verification code. The account cannot be used until the code is confirmed via /verify-email.
name
string
required
Display name. 2–50 characters, letters only (including accented characters). No three consecutive repeated letters.
email
string
required
Email address. Must be unique.
password
string
required
Minimum 8 characters; must contain at least one uppercase letter, one lowercase letter, and one digit.
birthDate
string
required
ISO 8601 date string (YYYY-MM-DD). User must be at least 18 years old.
weight
number
Body weight in kg (40–300). Used to pre-compute profileComplete.
height
number
Height in cm (50–210). Used to pre-compute profileComplete.
alergia
string
Free-text allergy description.
Response 201
{
  "success": true,
  "needsVerification": true,
  "email": "maria@example.com",
  "message": "Cuenta creada. Revisa tu correo para verificar."
}
Error responses
StatusCondition
400Name validation failed
400birthDate missing or invalid
400User is under 18
400Email already registered (verified)
400Email already registered but unverified — code is resent, needsVerification: true
curl example
curl -X POST https://api.healtyhelp.com/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "María García",
    "email": "maria@example.com",
    "password": "SecurePass1",
    "birthDate": "1995-06-15"
  }'

POST /api/auth/login

Authenticates an existing verified user. Implements progressive account lockout after 5 failed attempts (15-minute lockout). A lockout alert email is sent on the 5th failed attempt.
email
string
required
Registered email address.
password
string
required
Account password.
Response 200
{
  "success": true,
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": { }
}
user contains the User object. Special case — Google-only account (no local password)
{
  "needsGooglePassword": true,
  "token": "eyJ...",
  "user": { },
  "message": "Esta cuenta fue creada con Google. Crea una contraseña para iniciar sesión también con tu correo."
}
Error responses
StatusCondition
401Invalid credentials
401Account not yet verified (needsVerification: true, email echoed back)
423Account locked; locked: true, lockUntil (Unix ms) returned
curl example
curl -X POST https://api.healtyhelp.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "maria@example.com",
    "password": "SecurePass1"
  }'

POST /api/auth/verify-email

Validates the 6-digit code sent during registration. On success the account is activated and a JWT is returned immediately so the user is logged in without a second step.
email
string
required
Email address of the account to verify.
code
string
required
6-digit verification code from the email. Codes expire after 15 minutes.
Response 200
{
  "success": true,
  "token": "eyJ...",
  "user": { }
}
Error responses
StatusCondition
400email or code missing
400Code invalid or expired

POST /api/auth/resend-code

Re-generates and sends a fresh verification code. Only works for accounts that are not yet verified.
email
string
required
Email address for the unverified account.
Response 200
{
  "success": true,
  "message": "Código reenviado"
}
Error responses
StatusCondition
404User not found
400Account is already verified

POST /api/auth/forgot-password

Sends a password-reset link to the user’s email address. The link is valid for 30 minutes. For security, a successful response is returned regardless of whether the email exists.
email
string
required
Email address associated with the account.
Response 200
{
  "success": true,
  "message": "Si el correo existe, recibirás un enlace"
}
Error responses
StatusCondition
400Account was created via Google and has no password
500Email delivery failed

PUT /api/auth/reset-password/:token

Sets a new password using the token received via the forgot-password email. Also clears any existing account lockout. Path parameter
ParamDescription
tokenRaw (un-hashed) reset token from the email link
password
string
required
New password. Must meet the same strength requirements as registration.
Response 200
{
  "success": true,
  "token": "eyJ..."
}
Error responses
StatusCondition
400Token invalid or expired
400Password does not meet requirements

GET /api/auth/me

Requires Authorization: Bearer <token>
Returns the full profile of the currently authenticated user, including the latest published terms version for client-side comparison. Response 200
{
  "user": {
    "id": "64a1f2c3d4e5f6a7b8c9d0e1",
    "name": "María García",
    "email": "maria@example.com",
    "activeTermsVersion": "1.2.0",
    ...
  }
}
Error responses
StatusCondition
401Missing or invalid token
500Server error

PUT /api/auth/profile

Requires Authorization: Bearer <token>
Updates the authenticated user’s profile fields. All body fields are optional; send only the ones to change. If weight + already-stored birthDate and height satisfy the validity constraints, profileComplete is automatically set to true.
name
string
New display name. Trimmed before saving.
password
string
New password. Must meet strength requirements. Not allowed for Google-only accounts.
weight
number
Body weight in kg. Will be cast with parseFloat.
alergia
string
Allergy notes. Trimmed before saving.
Response 200
{
  "user": { },
  "message": "Perfil actualizado"
}
Error responses
StatusCondition
400Password change attempted on a Google-only account
400New password fails validation
500Save error

PUT /api/auth/avatar

Requires Authorization: Bearer <token>
Uploads a new avatar image via multipart form data. If the user already has a Cloudinary avatar, the previous image is deleted first. Request Content-Type: multipart/form-data
FieldTypeDescription
avatarFileImage file to upload
Response 200
{
  "user": { },
  "message": "Avatar actualizado"
}
Error responses
StatusCondition
400No file received
500Upload or save error

DELETE /api/auth/avatar

Requires Authorization: Bearer <token>
Removes the user’s current avatar from Cloudinary and clears the avatar field. Response 200
{
  "message": "Avatar eliminado",
  "user": { }
}

DELETE /api/auth/account

Requires Authorization: Bearer <token>
Permanently deletes the authenticated user’s account. Cascades to:
  • All Consumo documents belonging to the user
  • All review (resenas) entries across all Recipe documents
  • Cloudinary avatar (if set)
isSuperAdmin accounts cannot be deleted.
confirmacion
string
required
Must be the exact string "ELIMINAR" to confirm deletion.
Response 200
{
  "success": true,
  "message": "Cuenta eliminada correctamente"
}
Error responses
StatusCondition
400confirmacion is not "ELIMINAR"
403Account is a Super Administrator
404User not found

POST /api/auth/accept-terms

Requires Authorization: Bearer <token>
Records that the user has accepted the currently active terms and conditions. The latest published terms version is looked up server-side and stored on the user document. Response 200
{
  "success": true,
  "version": "1.2.0"
}

POST /api/auth/complete-profile

Requires Authorization: Bearer <token>
Completes the user’s health profile. If birthDate is provided, it takes priority; otherwise age (integer) is used to derive an approximate birth date. Once all constraints are satisfied profileComplete is set to true.
birthDate
string
ISO 8601 date string. Takes priority over age if provided.
age
number
Integer age in years. Used only when no birthDate is provided and no birthDate is already stored. Minimum 18.
weight
number
required
Body weight in kg. Must be between 40 and 300.
height
number
required
Height in cm. Must be between 50 and 210.
alergia
string
Allergy notes. Trimmed before saving.
Response 200
{
  "success": true,
  "user": { }
}
Error responses
StatusCondition
400birthDate invalid or in the future
400Neither birthDate stored nor valid age supplied
400Computed age is under 18
400weight out of range (40–300 kg)
400height out of range (50–210 cm)
404User not found

PATCH /api/auth/preferences

Requires Authorization: Bearer <token>
Updates auto-logout session preferences. At least one field must be provided.
autoLogoutEnabled
boolean
Enable or disable auto-logout on inactivity.
autoLogoutMinutes
number
Idle minutes before logout. Must be an integer between 1 and 480.
Response 200
{
  "success": true,
  "preferences": {
    "autoLogoutEnabled": true,
    "autoLogoutMinutes": 30
  }
}
Error responses
StatusCondition
400autoLogoutMinutes not between 1 and 480
400No valid preferences sent

GET /api/auth/google

Initiates the Google OAuth 2.0 flow. Redirects the browser to Google’s consent screen requesting profile and email scopes. This is a browser-redirect endpoint, not an API call. Flow
  1. Client navigates to GET /api/auth/google.
  2. Server redirects to Google.
  3. Google redirects back to /api/auth/google/callback.
  4. On success, the server redirects to {FRONTEND_URL}/google-callback?token=<jwt>.
  5. On failure, the server redirects to {FRONTEND_URL}/login?error=auth_failed.

GET /api/auth/google/callback

Handled internally by Passport.js. On success, issues a JWT and redirects to the frontend. On failure, redirects with ?error=auth_failed. Do not call this endpoint directly.

POST /api/auth/set-google-password

Requires Authorization: Bearer <token>
Sets a local password on a Google OAuth account that has none. Allows the user to also sign in with email + password. Can only be called once — once a password is set this endpoint returns 400.
password
string
required
New password. Must meet strength requirements (8+ chars, upper, lower, digit).
Response 200
{
  "success": true,
  "token": "eyJ...",
  "user": { }
}
Error responses
StatusCondition
400Password fails validation
400Account is not a Google account
400Account already has a password
404User not found

Build docs developers (and LLMs) love