ServiciosYa provides three password-management endpoints. Authenticated users change their password directly throughDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/CodexaCP/SERVICIOS-BACK/llms.txt
Use this file to discover all available pages before exploring further.
POST /api/auth/change-password. Users who have forgotten their credentials follow a two-step OTP flow: they request a one-time code via POST /api/auth/forgot-password and then submit that code alongside their new password via POST /api/auth/reset-password. All three endpoints enforce the same password policy before persisting any changes.
Password policy
All new passwords must satisfy every one of the following rules enforced byPasswordPolicy.IsValid:
| Rule | Requirement |
|---|---|
| Minimum length | At least 8 characters |
| Uppercase | At least 1 uppercase letter |
| Lowercase | At least 1 lowercase letter |
| Digit | At least 1 numeric digit |
| Special character | At least 1 character that is not a letter or digit |
“La contraseña debe tener mínimo 8 caracteres, una mayúscula, una minúscula, un número y un carácter especial.”
POST /api/auth/change-password
| Method | URL |
|---|---|
POST | /api/auth/change-password |
POST | /api/v1/auth/change-password |
ChangeUserPassword stored procedure.
On success, the MustChangePassword flag is cleared in the database, granting full access.
Request body
The user’s current password. Must match the hash stored in the database; the stored procedure will throw if it does not match.
The desired new password. Must pass the password policy checked by the API before the database call is made.
Response fields
"Password actualizado" on success.Example request
Example response
Error responses
| HTTP status | Body | Cause |
|---|---|---|
400 Bad Request | {"error": "La contraseña debe tener mínimo 8 caracteres..."} | New password does not meet the policy |
401 Unauthorized | — | Missing or invalid Bearer token |
500 / DB error | SQL-thrown message | Current password does not match ("Password actual inválido.") |
Action = "CHANGE_PASSWORD" and Result = "Success" is written on every successful call.
POST /api/auth/forgot-password
| Method | URL |
|---|---|
POST | /api/auth/forgot-password |
POST | /api/v1/auth/forgot-password |
200 OK regardless of whether the email address exists in the system. This design prevents user enumeration attacks — callers cannot determine whether an account exists by observing the response.
Rate limiting
The API enforces a rate limit per email address: a maximum of 3 requests are allowed within any rolling 15-minute window. Requests that exceed this limit are silently dropped (the response is still200 OK).
OTP details
| Property | Default value | Configuration key |
|---|---|---|
| Digit count | 6 (range: 6–8) | PasswordReset:OtpDigits |
| Expiry | 10 minutes | PasswordReset:ExpirationMinutes (clamped to 10–15) |
| Max requests per window | 3 | PasswordReset:MaxRequestsPerWindow |
| Window duration | 15 minutes | PasswordReset:RequestWindowMinutes |
Request body
Email address of the account for which the password reset is requested. Must not be blank; returns
400 if empty.Company scope for the lookup. Defaults to
1 (ServiciosYa base company) when the value is 0 or negative.Response fields
Always
"Si el correo existe, te enviaremos instrucciones para restablecer tu contrasena." — the message is the same whether or not the account was found.Example request
Example response
Error responses
| HTTP status | Body | Cause |
|---|---|---|
400 Bad Request | {"error": "El correo es obligatorio."} | email field is blank or missing |
The OTP code is transmitted to the user’s email in plain text. The API stores only the SHA-256 hash — the plain text is never persisted. When the user submits the code to
/api/auth/reset-password, the API hashes the submitted value before comparing it to the stored hash.POST /api/auth/reset-password
| Method | URL |
|---|---|
POST | /api/auth/reset-password |
POST | /api/v1/auth/reset-password |
otpCode with SHA-256 and compares it against the stored hash.
Each OTP record allows a maximum of 5 failed attempts before it is permanently invalidated, even if it has not yet expired. This prevents brute-forcing of the 6-digit space.
Request body
Email address of the account being reset.
Company scope for the lookup. Defaults to
1 when 0 or negative.The plain-text OTP code received in the reset email (e.g.
"482910"). Must not be blank.The new password. Must pass the password policy before the OTP is validated.
Response fields
"Tu contrasena fue actualizada." on success.Example request
Example response
Error responses
| HTTP status | Body | Cause |
|---|---|---|
400 Bad Request | {"error": "Correo, codigo y nueva contrasena son obligatorios."} | One or more required fields are blank |
400 Bad Request | {"error": "La contraseña debe tener mínimo 8 caracteres..."} | New password fails the policy check |
400 / DB error | SQL-thrown message | OTP expired, maximum attempts exceeded, or OTP not found |