Referencia de la API
Todas las rutas que sirve la API de Learnio, quién puede llamarlas y cómo funcionan el inicio de sesión, los permisos, los errores y la paginación.
Para el paquete Full Stack
URL base y formato de respuesta
Todas las rutas se sirven con el prefijo /api. En local, la URL base es http://localhost:8000/api. En un servidor es la dirección de tu API seguida de /api, el mismo valor que ambos frontends leen de NEXT_PUBLIC_API_BASE_URL (Variables de entorno).
La API sirve a dos públicos que nunca comparten un token. Los estudiantes usan las rutas de /api/users/<area> y /api/shop, que se enumeran en las secciones para estudiantes más abajo. El panel de administración usa todas las demás rutas, incluidas /api/users y /api/users/<username>, que gestionan las cuentas de los estudiantes.
Los cuerpos de las solicitudes son JSON, excepto la subida de archivos. Cada respuesta llega en el mismo envoltorio:
{
"success": true,
"data": { },
"message": ""
}data contiene el resultado. message es una frase corta que rellenan algunas escrituras, traducida al idioma de la solicitud, y vacía en los demás casos. La comprobación de estado no necesita token y muestra el envoltorio:
curl http://localhost:8000/api/health{"success":true,"data":{"status":"ok"},"message":""}Responde 503 mientras no se puede acceder a la base de datos o esta no tiene tablas, así que un balanceador de carga puede usarla como sonda de disponibilidad.
Errores
Una solicitud fallida responde con el estado HTTP correspondiente y el mismo sobre, con success: false, data: null y, en la validación, los problemas por campo, con el nombre del campo como clave (un campo dentro de un objeto anidado, con su ruta separada por puntos):
curl -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"not-an-email","password":"x"}'{
"success": false,
"data": null,
"message": "Enter a valid email address (example@domain.com).",
"errors": {
"email": ["Enter a valid email address (example@domain.com)."]
}
}| Estado | Cuándo |
|---|---|
400 | Un campo no superó la validación, un valor de la consulta no es válido o el cuerpo contiene un campo que la ruta no acepta. Los campos desconocidos se rechazan, no se ignoran. |
401 | El token falta, ha caducado o pertenece al otro público. También un inicio de sesión fallido, tanto si el email no tiene cuenta como si la contraseña es incorrecta. |
403 | Los roles del administrador no conceden el permiso de la ruta, o una cuenta de instructor intentó acceder fuera de sus propios cursos. |
404 | No existe ese registro. |
409 | La escritura entra en conflicto con un registro existente, como un correo o un slug ya en uso. |
429 | Demasiados intentos desde una misma dirección en una ruta de inicio de sesión, registro o contraseña. La cabecera Retry-After indica cuántos segundos esperar. |
500 | Un fallo inesperado. El mensaje sigue siendo genérico y los detalles van al registro de la API. |
Las escrituras correctas responden 201 para POST y 200 para los demás métodos.
Paginación y ordenación
Las listas llegan en dos formas, una por público. Las rutas de estudiantes responden con la forma que lee el sitio para estudiantes; las rutas de administración responden con la forma que lee el panel.
| Listas públicas y de estudiantes | Listas de administración | |
|---|---|---|
| Página | page, desde 1 | page, desde 1 |
| Tamaño de página | page_count (cursos, blog, inscripciones, reseñas) o per_page (instructores). Los cursos usan por defecto el ajuste courses_per_page; las inscripciones, 100. | page_count, 15 por defecto (10 para administradores). Los pedidos usan limit. |
| Ordenación | Solo cursos: sort_by y sort_dir (asc o desc) | sort y order (asc o desc). Los pedidos usan sort_by y sort_order. |
| Orden predeterminado | Cursos por actualización más reciente, blog por publicación más reciente | Primero los actualizados más recientemente, con los empates resueltos por id. Las categorías y los instructores mantienen su orden curado. |
| Respuesta | data, current_page, last_page, per_page, total, from, to, más los enlaces de página | data, page, limit, total, totalPages |
Una página tiene como máximo 100 filas: un tamaño mayor se lee como 100, y uno ausente o ilegible vuelve al valor por defecto de la lista. Lo mismo ocurre con page, que vuelve a 1.
sort solo acepta las columnas que permite cada lista. Una clave desconocida recurre al orden predeterminado en lugar de fallar, así que un marcador antiguo sigue cargando.
La lista pública de cursos se ordena por id, price, discount_percentage, rating, duration, level, language, created_at o updated_at, y se filtra por title, category_id, instructor_id y type (live o recorded).
Idioma
Envía el idioma del lector en la cabecera Accept-Language. La API habla los idiomas indicados en back-end/src/i18n/locales.ts, en y ar tal como viene. Lee la primera etiqueta, así que ar-SA es árabe, y una solicitud que no nombra ningún idioma admitido se responde en el idioma del ajuste default_locale. No hay parámetro de consulta para el idioma.
- Los mensajes de error y el
messagede una escritura correcta se traducen. - El texto guardado en ambos idiomas, como los títulos y las descripciones de los cursos, vuelve como
{ "en": "...", "ar": "..." }y el cliente elige uno. - Algunas rutas de estudiantes responden solo en el idioma solicitado: la lista de inscripciones, el contenido de un curso y la búsqueda.
- El pago toma el idioma de su cuerpo (
locale, uno de los idiomas admitidos), para que el recibo coincida con la página en la que compró el estudiante.
Autenticación
Los estudiantes y los administradores inician sesión en endpoints distintos, contra tablas distintas, y reciben tokens que solo aceptan sus propias rutas.
| Público | Inicio de sesión | Token en la respuesta | Aceptado en |
|---|---|---|---|
| Estudiante | POST /api/users/auth/login | data.token, con data.user | Rutas de estudiantes |
| Panel de administración | POST /api/auth/login | data.access_token, con data.admin (roles y permisos) | Rutas de administración |
- Ambos son JWT firmados con
JWT_SECRET. Envíalos comoAuthorization: Bearer <token>. - Un token dura
JWT_EXPIRATION,7dpor defecto (Variables de entorno). El inicio de sesión de administrador indica el mismo valor enexpires_in. - No hay endpoint de renovación. Cuando un token caduca, la siguiente solicitud responde
401y el cliente vuelve a iniciar sesión. - Cerrar sesión (
POST /api/users/auth/logout) solo le indica al cliente que descarte su token. No se revoca nada en el servidor, así que un token sigue siendo válido hasta que caduca. - Un token de estudiante se rechaza en las rutas de administración y un token de administrador en las rutas de estudiantes, aunque ambos usan el mismo secreto.
- Un inicio de sesión fallido responde
401con un único mensaje, tanto si el email no tiene cuenta como si la contraseña es incorrecta, así que el formulario no sirve para averiguar quién tiene cuenta. - Las rutas de inicio de sesión, registro y contraseña aceptan 10 intentos por minuto desde una misma dirección, contados por ruta. Pasado eso responden
429con una cabeceraRetry-After. La cuenta se guarda en la memoria de la API, así que se reinicia al reiniciarla y cada instancia lleva la suya.
Inicia sesión como el Super Admin de los datos iniciales
Terminalcurl -X POST http://localhost:8000/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"admin@learnio.com","password":"Admin@123"}'Respuesta{ "success": true, "data": { "access_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_in": "7d", "admin": { "id": 1, "email": "admin@learnio.com", "instructor_id": null, "roles": [{ "id": 1, "name": "Super Admin", "guard_name": "web" }], "permissions": ["admins.view", "admins.create", "..."] } }, "message": "Signed in successfully." }Llama a una ruta protegida con el token
Terminalcurl "http://localhost:8000/api/courses?page=1&page_count=5" \ -H "Authorization: Bearer <access_token>"Resultado esperado: Los cinco primeros cursos, con la forma de lista de administración.
Inicia sesión como el estudiante de los datos iniciales
Los datos de ejemplo también incluyen un estudiante,
demo@learnio.comcon la contraseñaDemo@123:Terminalcurl -X POST http://localhost:8000/api/users/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"demo@learnio.com","password":"Demo@123"}'Después pasa
data.tokende la misma forma, por ejemplo aGET /api/users/enrollments.
Cambia las contraseñas de los datos iniciales
Las cuentas de los datos de ejemplo usan contraseñas publicadas: Admin@123 para el Super Admin, admin123 para el resto del personal y Demo@123 para el estudiante de demostración. Cámbialas, o empieza con las tablas vacías, antes de que un sitio pase a producción.
Permisos
Cada ruta de administración comprueba primero el token y luego el permiso que indica. Los permisos se llaman <module>.<action>, y un administrador tiene todos los permisos de todos sus roles. Cuando una ruta indica varios, basta con uno de ellos. En las tablas de administración de más abajo, un nombre de permiso en la columna Quién puede llamarla significa un administrador cuyos roles lo conceden.
Volver a ejecutar el seeder crea los roles que faltan y deja como están los permisos de los roles existentes, así que los cambios hechos en el panel se conservan. Super Admin es la excepción: recibe cualquier permiso que aún no tenga.
| Módulo | Permisos |
|---|---|
| Administradores | admins.view, admins.create, admins.edit, admins.delete, admins.assign_roles |
| Roles | roles.view, roles.create, roles.edit, roles.delete, roles.assign_permissions |
| Ajustes | settings.view, settings.edit |
| Estudiantes | students.view, students.create, students.update, students.delete, students.restore, students.verify |
| Categorías | categories.view, categories.create, categories.edit, categories.delete, categories.restore |
| Cursos | courses.view, courses.create, courses.edit, courses.delete, courses.restore |
| Plan de estudios | curriculum.view, curriculum.create, curriculum.edit, curriculum.delete |
| Instructores | instructors.view, instructors.create, instructors.edit, instructors.delete, instructors.restore |
| Inscripciones | enrollments.view, enrollments.create, enrollments.edit, enrollments.delete |
| Pedidos | orders.view, orders.create, orders.edit, orders.delete |
| Reseñas | reviews.view, reviews.edit, reviews.delete, reviews.restore |
| Clases en vivo | live_sessions.view, live_sessions.create, live_sessions.edit, live_sessions.delete |
| Tareas | assignments.view, assignments.create, assignments.edit, assignments.delete |
| Blog | blog.view, blog.create, blog.edit, blog.delete, blog.restore |
| Asistente de IA | ai_chat.use, ai_chat.view_models |
Todos los permisos de lectura terminan en .view y ningún otro lo hace: el rol Viewer de los datos iniciales se construye con esa regla. Los roles que crean los datos de ejemplo:
| Rol | Concede |
|---|---|
| Super Admin | Todo |
| Panel de administración | Todo excepto roles.*, admins.* y settings.edit |
| Manager | Cursos, plan de estudios, categorías, instructores, inscripciones y pedidos sin eliminaciones, más students.view, reviews.view y reviews.edit |
| Editor | blog.*, reviews.view, reviews.edit, categories.view, courses.view, instructors.view |
| Viewer | Todos los permisos .view |
| Instructor | Clases en vivo, tareas y plan de estudios, courses.view, courses.create, courses.edit, y lectura de estudiantes, inscripciones y reseñas |
Una cuenta de administrador vinculada a un instructor lleva un instructor_id en su respuesta de inicio de sesión y, además de sus permisos, queda limitada a sus propios cursos: las listas solo muestran esos cursos y sus estudiantes, y una escritura fuera de ellos responde 403.
Cuando cambian los roles de un administrador, el panel recibe el aviso por el socket /auth (evento permissions-updated) para refrescar GET /api/auth/me. Ese socket solo acepta tokens de administrador.
Catálogo público
No se necesita token. Son las rutas que llaman las páginas públicas del sitio para estudiantes.
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/health | Cualquiera | Comprobación de disponibilidad |
GET | /api/users/courses | Cualquiera | Lista los cursos públicos publicados, paginados (page_count, el ajuste courses_per_page por defecto), con filtros y ordenación |
GET | /api/users/courses/categories | Cualquiera | Las categorías que tienen al menos un curso público, con sus recuentos |
GET | /api/users/courses/:slug | Cualquiera | Un curso público publicado con sus secciones y lecciones. Un borrador responde 404. Solo las lecciones de vista previa gratuita incluyen su contenido y su vídeo. |
GET | /api/users/courses/:slug/reviews | Cualquiera | Las reseñas publicadas del curso, de la actualizada más recientemente a la más antigua, paginadas (page_count, 5 por defecto) |
GET | /api/users/Instructors | Cualquiera | Directorio de instructores, paginado (per_page, 8 por defecto), con filtro por specialty |
GET | /api/users/Instructors/:username | Cualquiera | Un instructor con sus cursos públicos |
GET | /api/users/blog | Cualquiera | Artículos publicados, del más reciente al más antiguo, paginados (page_count, 9 por defecto), con filtro por tag |
GET | /api/users/blog/tags | Cualquiera | Todas las etiquetas en uso, con cuántos artículos las llevan |
GET | /api/users/blog/:slug | Cualquiera | Un artículo publicado |
GET | /api/users/platform/figures | Cualquiera | Los recuentos de la página de inicio: estudiantes, cursos, instructores, países y satisfacción |
GET | /api/categories | Cualquiera | Lista de categorías, paginada, con search, is_active, parent_id, has_courses |
GET | /api/categories/roots | Cualquiera | Categorías de nivel superior |
GET | /api/categories/slug/:slug | Cualquiera | Una categoría por slug |
GET | /api/categories/:id | Cualquiera | Una categoría por id |
GET | /api/helpers/countries | Cualquiera | Países para un campo de selección, en el idioma de la solicitud |
GET | /api/shop/payment-methods | Cualquiera | Los métodos de pago que debe ofrecer el pago, y cuáles de ellos son alojados |
La I mayúscula de /api/users/Instructors es la ruta que llama el sitio para estudiantes; la coincidencia no distingue mayúsculas de minúsculas.
Registro e inicio de sesión de estudiantes
El sitio para estudiantes usa las rutas de /api/users/auth. El registro inicia la sesión del estudiante al momento y envía por correo un enlace de confirmación; una cuenta sin confirmar puede igualmente navegar y comprar.
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
POST | /api/users/auth/register | Cualquiera | Crea la cuenta (first_name, last_name, email, password de 8 caracteres o más, phone opcional) e inicia sesión. data.verification_email_sent indica si el correo salió. |
POST | /api/users/auth/login | Cualquiera | Inicia sesión con email y password, y responde token y user |
POST | /api/users/auth/logout | Cualquiera | No hay nada que revocar; permite al cliente borrar su token |
POST | /api/users/auth/resend | Cualquiera | Vuelve a enviar el enlace de confirmación a email |
POST | /api/users/auth/verify-email | Cualquiera | Confirma la dirección con el token del enlace (válido 24 horas) |
POST | /api/users/auth/forgot-password | Cualquiera | Envía un enlace de restablecimiento a email (válido 1 hora) |
POST | /api/users/auth/reset-password | Cualquiera | Establece una nueva password con el token del enlace |
GET | /api/users/auth/me | Estudiante | El estudiante con sesión iniciada |
resend y forgot-password responden igual tanto si la dirección tiene cuenta como si no, así que no sirven para averiguar quién está registrado. El inicio de sesión, el registro, resend, forgot-password y reset-password tienen límite de intentos (Autenticación).
Un segundo conjunto de rutas de estudiantes en /api/students/auth trabaja con las mismas cuentas y también responde token y user. El sitio para estudiantes no lo usa; usa preferiblemente /api/users/auth.
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
POST | /api/students/auth/register | Cualquiera | Crea una cuenta de estudiante e inicia sesión, sin correo de confirmación |
POST | /api/students/auth/login | Cualquiera | Inicia sesión |
GET | /api/students/auth/me | Estudiante | El perfil del estudiante con sesión iniciada |
PATCH | /api/students/auth/me | Estudiante | Actualiza el nombre, el correo o el teléfono |
PATCH | /api/students/auth/me/password | Estudiante | Cambia la contraseña |
POST | /api/students/auth/forgot-password | Cualquiera | Envía un enlace de restablecimiento a email, y responde igual tanto si la dirección tiene cuenta como si no |
POST | /api/students/auth/reset-password | Cualquiera | Establece una nueva contraseña con un token de restablecimiento |
Perfil, cursos y progreso del estudiante
Todas estas rutas necesitan un token de estudiante. Los cursos y las lecciones se identifican por su code, no por su id numérico.
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/users/profile | Estudiante | El estudiante con sesión iniciada |
PATCH | /api/users/profile | Estudiante | Actualiza first_name, last_name, email o phone |
PATCH | /api/users/profile/password | Estudiante | Cambia la contraseña (la actual y una nueva de 8 caracteres o más) |
GET | /api/users/dashboard/overview | Estudiante | Todo lo que muestra la pantalla de inicio del panel, en una sola llamada |
GET | /api/users/dashboard/kpis | Estudiante | Las cifras principales del estudiante |
GET | /api/users/dashboard/radar | Estudiante | El gráfico de habilidades, a partir del ajuste dashboard_radar_metrics |
GET | /api/users/enrollments | Estudiante | Los cursos del estudiante, paginados (page_count, 100 por defecto), con filtro por type, search y status |
GET | /api/users/enrollments/courses/:code | Estudiante | El contenido completo de un curso que tiene el estudiante, con el estado de cada lección y el progreso |
PATCH | /api/users/enrollments/courses/:code | Estudiante | Registra la última lección abierta (last_accessed_lesson_id) |
POST | /api/users/enrollments/lessons/:lessonCode/complete | Estudiante | Marca una lección como completada y actualiza el progreso del curso |
GET | /api/users/enrollments/lessons/:lessonCode/note | Estudiante | La nota del estudiante sobre una lección |
PUT | /api/users/enrollments/lessons/:lessonCode/note | Estudiante | Guarda la nota (body) |
GET | /api/users/search | Estudiante | Búsqueda global (q, limit por tipo): los cursos del estudiante, el catálogo, los instructores y más |
GET | /api/users/courses/:courseId/review | Estudiante | La reseña del propio estudiante sobre el curso, o null si no tiene |
PUT | /api/users/courses/:courseId/review | Estudiante | Escribe o sustituye la reseña del estudiante: rating de 1 a 5 y comment opcional de hasta 2.000 caracteres |
DELETE | /api/users/courses/:courseId/review | Estudiante | Retira la reseña del estudiante |
Las rutas de reseñas usan el id numérico del curso, y cada estudiante tiene una reseña por curso. Solo puede escribirla un estudiante inscrito en el curso; una inscripción cancelada responde 403.
- Una reseña queda
publishedal instante, opendinghasta que un moderador la apruebe cuando el ajustereviews_require_approvalvaletrue. Editar una reseña que un moderador ocultó la devuelve apending. - Una reseña que eliminó un moderador vuelve con
status: removedy ya no se puede editar ni retirar (403). - Cada escritura recalcula la valoración y el número de reseñas del curso, y los de su instructor.
- Una reseña nueva, y una edición que espera aprobación, notifican al personal que tiene
reviews.view.
Cuestionarios, tareas y calendario
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/users/quizzes?course_id= | Estudiante | Los cuestionarios de un curso que tiene el estudiante |
GET | /api/users/quizzes/:id | Estudiante | Un cuestionario con sus preguntas, sin las respuestas |
GET | /api/users/quizzes/:id/attempts | Estudiante | Los intentos anteriores del estudiante |
POST | /api/users/quizzes/:id/attempts | Estudiante | Envía answers (id de la pregunta con los ids de las opciones elegidas) y devuelve la puntuación |
GET | /api/users/dashboard/calendar | Estudiante | Las clases y las fechas límite de las tareas entre from y to (fechas ISO, 7 días por defecto, 92 como máximo) |
POST | /api/users/dashboard/calendar/assignments/:id/submit | Estudiante | Entrega una tarea (body) |
DELETE | /api/users/dashboard/calendar/assignments/:id/submit | Estudiante | Retira una entrega |
Las rutas de clases en vivo del calendario se describen en Clases en vivo.
Mensajes y notificaciones del estudiante
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/users/conversations | Estudiante | Las conversaciones del estudiante con sus instructores |
POST | /api/users/conversations | Estudiante | Abre, o devuelve, la conversación con el instructor de course_id |
GET | /api/users/conversations/:id/messages | Estudiante | Los mensajes de una conversación |
POST | /api/users/conversations/:id/messages | Estudiante | Envía un mensaje: body, una imagen (attachment_url, attachment_name, attachment_type), o ambos |
PATCH | /api/users/conversations/:id/read | Estudiante | Marca la conversación como leída |
PATCH | /api/users/conversations/:id/unread | Estudiante | La marca como no leída |
GET | /api/users/notifications | Estudiante | Las notificaciones del estudiante |
PATCH | /api/users/notifications/:id/read | Estudiante | Marca una como leída |
PATCH | /api/users/notifications/read-all | Estudiante | Marca todas como leídas |
DELETE | /api/users/notifications/:id | Estudiante | Elimina una |
Las notificaciones nuevas también se envían por Socket.IO, en el namespace /notifications en la dirección de la API sin /api. Pasa el token como auth.token en el handshake y escucha notification:created. Los administradores usan el mismo socket con su propio token.
Pago y cobros
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/shop/payment-methods | Cualquiera | Los methods que ofrece el pago y cuáles son hosted |
POST | /api/shop/checkout | Estudiante | Compra course_id, o hasta 50 course_ids en un solo cobro, con payment_method (card o paypal) y locale |
POST | /api/shop/orders/:reference/settle | Estudiante | Finaliza un pago alojado cuando vuelve el comprador. Es necesario para PayPal; no hace nada para Stripe. |
GET | /api/shop/orders | Estudiante | Los pedidos del estudiante |
POST | /api/webhooks/payments/stripe | Stripe, firmado | Liquida, marca como fallidos o reembolsa pedidos a partir de los eventos de Stripe |
POST | /api/webhooks/payments/paypal | PayPal, firmado | Liquida, marca como fallidos o reembolsa pedidos a partir de los eventos de PayPal |
Cuando el pago responde con redirect_url, envía allí al comprador y trata el pedido como pending: la plaza se concede cuando el webhook del procesador confirma el pago, no al volver. Cada webhook comprueba la firma del procesador y responde 401 cuando no coincide. Los eventos se aplican una sola vez, por mucho que el procesador reintente.
Un curso gratuito (precio 0) pasa por la misma ruta y nunca llega a un procesador, así que funciona sin ninguna clave de pago. El pedido se guarda como paid con gateway: "free" y redirect_url: null, la plaza se concede al momento y el estudiante recibe el email de inscripción sin recibo. Los pedidos gratuitos cuentan como inscripciones, no como ventas: quedan fuera del valor medio de pedido.
Configuración de los procesadores y sus suscripciones a webhooks: Pagos.
Inicio de sesión de administradores y cuentas del personal
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
POST | /api/auth/login | Cualquiera | Inicia la sesión de un administrador; responde access_token, roles y permisos. Con límite de intentos. |
GET | /api/auth/me | Cualquier administrador con sesión iniciada | El administrador con sesión iniciada, con sus roles y permisos |
GET | /api/admins | admins.view | Lista del personal, con filtro por email, name, phone, role_id |
GET | /api/admins/statistics | admins.view | Recuentos del personal |
GET | /api/admins/:id | admins.view | Un administrador |
POST | /api/admins | admins.create | Crea un administrador |
PATCH | /api/admins/:id | admins.edit | Actualiza un administrador |
PATCH | /api/admins/:id/roles | admins.assign_roles | Sustituye los roles del administrador (role_ids) |
DELETE | /api/admins/:id | admins.delete | Elimina un administrador |
PATCH | /api/admins/profile | Cualquier administrador con sesión iniciada | Actualiza el nombre, los datos de contacto y la foto del propio administrador con sesión iniciada |
PATCH | /api/admins/profile/password | Cualquier administrador con sesión iniciada | Cambia la contraseña del propio administrador con sesión iniciada |
Una dirección de email pertenece a un solo administrador, incluso a uno eliminado: crear un administrador, o cambiar un email por uno ya usado, responde 409.
Roles
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/roles | roles.view | Roles, paginados cuando se envía page, con filtro por name, guard_name, created_from, created_to |
GET | /api/roles/statistics | roles.view | Recuentos de roles |
GET | /api/roles/select | roles.view | Todos los roles, para un selector |
GET | /api/roles/permissions | roles.view | Todos los permisos, agrupados por módulo |
GET | /api/roles/:id | roles.view | Un rol con sus permisos |
POST | /api/roles | roles.create | Crea un rol (name) |
PUT | /api/roles/:id | roles.edit | Cambia el nombre de un rol |
POST | /api/roles/:id/permissions | roles.assign_permissions | Sustituye los permisos del rol por permissions, una lista de nombres |
DELETE | /api/roles/:id | roles.delete | Elimina un rol |
Estudiantes
Las cuentas de estudiantes se identifican por username. Eliminar una es un borrado lógico que se puede restaurar.
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/users | students.view | Estudiantes, con search, email, phone, country_id, username, first_name, last_name, from_date, to_date, verified |
GET | /api/users/statistic | students.view | Recuentos de estudiantes |
GET | /api/users/:username | students.view | Un estudiante |
POST | /api/users | students.create | Crea un estudiante |
PATCH | /api/users/:username | students.update | Actualiza un estudiante |
PATCH | /api/users/:username/change-password | students.update | Establece la contraseña de un estudiante |
POST | /api/users/:username/resend-verification-email | students.update | Vuelve a enviar el enlace de confirmación. data.sent vale false y data.simulated vale true cuando no hay proveedor de correo y el enlace fue al registro. 409 si ya está confirmado, 429 cuando la dirección recibió demasiados, 503 cuando el proveedor lo rechazó. |
POST | /api/users/:username/make-verified | students.verify | Marca el correo como confirmado |
POST | /api/users/:username/make-unverified | students.verify | Marca el correo como no confirmado |
DELETE | /api/users/:username | students.delete | Mueve el estudiante a la papelera |
GET | /api/users/deleted | students.view, students.delete o students.restore | Estudiantes eliminados |
GET | /api/users/deleted/:username | students.view, students.delete o students.restore | Un estudiante eliminado |
POST | /api/users/deleted/:username/restore | students.restore | Restaura un estudiante eliminado |
Instructores
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/instructors | instructors.view | Instructores, con search, specialty, status, is_featured |
GET | /api/instructors/statistic | instructors.view | Recuentos de instructores |
GET | /api/instructors/username/:username | instructors.view | Un instructor por nombre de usuario |
GET | /api/instructors/:id | instructors.view | Un instructor |
POST | /api/instructors | instructors.create | Crea un instructor |
PATCH | /api/instructors/:id | instructors.edit | Actualiza un instructor |
DELETE | /api/instructors/:id | instructors.delete | Mueve un instructor a la papelera |
GET | /api/instructors/deleted | instructors.view, instructors.delete o instructors.restore | Instructores eliminados |
POST | /api/instructors/deleted/:id/restore | instructors.restore | Restaura uno |
Una cuenta de instructor escribe a sus estudiantes mediante estas rutas, que responden 403 para un administrador no vinculado a un instructor:
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/conversations | Cuenta de instructor | Las conversaciones del instructor |
GET | /api/conversations/with/:userId | Cuenta de instructor | Los cursos que el instructor comparte con un estudiante, para iniciar una conversación desde ellos |
POST | /api/conversations | Cuenta de instructor | Abre, o devuelve, una conversación con user_id, opcionalmente sobre course_id |
GET | /api/conversations/:id/messages | Cuenta de instructor | Los mensajes de una conversación |
POST | /api/conversations/:id/messages | Cuenta de instructor | Envía un mensaje |
PATCH | /api/conversations/:id/read | Cuenta de instructor | La marca como leída |
PATCH | /api/conversations/:id/unread | Cuenta de instructor | La marca como no leída |
Categorías
Las lecturas están abiertas a cualquiera y se enumeran en el Catálogo público. Las escrituras necesitan un permiso:
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/categories/statistic | categories.view | Recuentos de categorías |
POST | /api/categories | categories.create | Crea una categoría |
PATCH | /api/categories/:id | categories.edit | Actualiza una categoría |
DELETE | /api/categories/:id | categories.delete | Mueve una categoría a la papelera |
GET | /api/categories/deleted | categories.delete o categories.restore | Categorías eliminadas |
POST | /api/categories/deleted/:id/restore | categories.restore | Restaura uno |
Cursos
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/courses | courses.view | Cursos, con search, category_id, instructor_id, status, type, is_public, is_featured |
GET | /api/courses/statistic | courses.view | Recuentos de cursos |
GET | /api/courses/slug/:slug | courses.view | Un curso por slug |
GET | /api/courses/:id | courses.view | Un curso |
POST | /api/courses | courses.create | Crea un curso |
PATCH | /api/courses/:id | courses.edit | Actualiza un curso |
DELETE | /api/courses/:id | courses.delete | Mueve un curso a la papelera |
GET | /api/courses/deleted | courses.delete o courses.restore | Cursos eliminados |
POST | /api/courses/deleted/:id/restore | courses.restore | Restaura uno |
Plan de estudios: secciones, lecciones y recursos
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/courses/:courseId/sections | curriculum.view | Las secciones de un curso |
POST | /api/courses/:courseId/sections | curriculum.create | Añade una sección |
POST | /api/courses/:courseId/sections/reorder | curriculum.edit | Define el orden de las secciones a partir de ids |
GET | /api/sections/:id | curriculum.view | Una sección |
PATCH | /api/sections/:id | curriculum.edit | Actualiza una sección |
DELETE | /api/sections/:id | curriculum.delete | Elimina una sección |
GET | /api/sections/:sectionId/lessons | curriculum.view | Las lecciones de una sección |
POST | /api/sections/:sectionId/lessons | curriculum.create | Añade una lección |
POST | /api/sections/:sectionId/lessons/reorder | curriculum.edit | Define el orden de las lecciones a partir de ids |
GET | /api/lessons/:id | curriculum.view | Una lección |
PATCH | /api/lessons/:id | curriculum.edit | Actualiza una lección |
DELETE | /api/lessons/:id | curriculum.delete | Elimina una lección |
GET | /api/lessons/:lessonId/resources | curriculum.view | Los recursos descargables de una lección |
POST | /api/lessons/:lessonId/resources | curriculum.edit | Adjunta un recurso |
PATCH | /api/lesson-resources/:id | curriculum.edit | Actualiza un recurso |
DELETE | /api/lesson-resources/:id | curriculum.edit | Quita un recurso |
Cuestionarios y tareas
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/quizzes?course_id= | courses.view | Los cuestionarios de un curso (course_id es obligatorio) |
GET | /api/quizzes/:id | courses.view | Un cuestionario con sus preguntas y respuestas |
POST | /api/quizzes | courses.create | Crea un cuestionario |
PATCH | /api/quizzes/:id | courses.edit | Actualiza un cuestionario |
DELETE | /api/quizzes/:id | courses.delete | Elimina un cuestionario |
POST | /api/quizzes/:id/questions | courses.edit | Añade una pregunta |
PATCH | /api/quizzes/:id/questions/:questionId | courses.edit | Actualiza una pregunta |
DELETE | /api/quizzes/:id/questions/:questionId | courses.edit | Elimina una pregunta |
GET | /api/assignments | assignments.view | Tareas, con search, course_id, lesson_id, status, from, to |
GET | /api/assignments/:id | assignments.view | Una tarea |
GET | /api/assignments/:id/submissions | assignments.view | Las entregas pendientes de calificar |
PATCH | /api/assignments/submissions/:submissionId/grade | assignments.edit | Califica una entrega |
POST | /api/assignments | assignments.create | Crea una tarea |
PATCH | /api/assignments/:id | assignments.edit | Actualiza una tarea |
DELETE | /api/assignments/:id | assignments.delete | Elimina una tarea |
Inscripciones y pedidos
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/enrollments | enrollments.view | Inscripciones, con search, course_id, user_id, status, date_from, date_to |
GET | /api/enrollments/statistic | enrollments.view | Recuentos de inscripciones |
GET | /api/enrollments/:id | enrollments.view | Una inscripción |
POST | /api/enrollments | enrollments.create | Inscribe a un estudiante manualmente |
PATCH | /api/enrollments/:id | enrollments.edit | Actualiza una inscripción |
DELETE | /api/enrollments/:id | enrollments.delete | Quita una inscripción |
GET | /api/orders | orders.view | Pedidos, con search, status, payment_method, course_id, user_id, date_from, date_to, page, limit, sort_by, sort_order |
GET | /api/orders/revenue | orders.view | Ingresos entre date_from y date_to. El valor medio de pedido deja fuera los pedidos gratuitos. |
GET | /api/orders/revenue/series | orders.view | Los ingresos diarios de los últimos days (30 por defecto, 365 como máximo) |
GET | /api/orders/:id | orders.view | Un pedido |
POST | /api/orders | orders.create | Registra una plaza pagada por otra vía |
PATCH | /api/orders/:id | orders.edit | Actualiza un pedido |
DELETE | /api/orders/:id | orders.delete | Elimina un pedido |
El status de un pedido es pending, paid, failed o refunded. Su gateway indica el procesador que cobró, demo para el simulador integrado o free para un curso que no costaba nada.
Reseñas
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/course-reviews | reviews.view | Reseñas, con search, course_id, user_id, rating, status |
GET | /api/course-reviews/statistic | reviews.view | Recuentos de reseñas |
GET | /api/course-reviews/:id | reviews.view | Una reseña |
PATCH | /api/course-reviews/:id | reviews.edit | Modera una reseña: status es published, pending o hidden |
DELETE | /api/course-reviews/:id | reviews.delete | Mueve una reseña a la papelera |
GET | /api/course-reviews/deleted | reviews.delete o reviews.restore | Reseñas eliminadas |
POST | /api/course-reviews/deleted/:id/restore | reviews.restore | Restaura uno |
Los estudiantes escriben sus propias reseñas mediante las rutas de estudiante, y la página del curso lee las publicadas del Catálogo público. Cada cambio de moderación recalcula la valoración del curso y la del instructor.
Blog
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/blog | blog.view | Artículos en cualquier estado, con search, category_slug, status, tag |
GET | /api/blog/statistic | blog.view | Recuentos de artículos |
GET | /api/blog/slug/:slug | blog.view | Un artículo por slug |
GET | /api/blog/:id | blog.view | Un artículo |
POST | /api/blog | blog.create | Crea un artículo |
PATCH | /api/blog/:id | blog.edit | Actualiza un artículo |
DELETE | /api/blog/:id | blog.delete | Mueve un artículo a la papelera |
GET | /api/blog/deleted | blog.delete o blog.restore | Artículos eliminados |
POST | /api/blog/deleted/:id/restore | blog.restore | Restaura uno |
Ajustes
Los ajustes de la plataforma se guardan como pares de clave y valor y se identifican por key.
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/settings | settings.view | Ajustes, con search, category, type |
GET | /api/settings/:key | settings.view | Un ajuste |
PATCH | /api/settings/:key | settings.edit | Cambia el valor de un ajuste |
DELETE | /api/settings/:key | settings.edit | Elimina un ajuste |
El seeder crea estos seis, y cada uno lo lee la API o el panel del estudiante:
| Clave | Valor inicial | Qué hace |
|---|---|---|
site_name | Learnio | El nombre del producto que aparece en cada email que envía la API |
default_locale | en | El idioma que se usa cuando una solicitud no nombra ningún idioma admitido. Un valor que no sea un idioma admitido se rechaza con 400. |
support_email | support@learnio.com | La dirección de respuesta de todos los emails, para que una respuesta llegue a una persona |
courses_per_page | 12 | El tamaño de página del catálogo público cuando la solicitud no indica ninguno (de 1 a 100) |
reviews_require_approval | false | Con true, la reseña de un estudiante espera como pending hasta que un moderador la publica |
dashboard_radar_metrics | Un mapa JSON de métrica a puntuación | El gráfico de habilidades del panel del estudiante |
Un cambio se aplica en la siguiente solicitud o el siguiente email, sin reiniciar. Volver a ejecutar el seeder añade un ajuste que falte, pero nunca sobrescribe un valor ya guardado.
Subida de archivos multimedia
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
POST | /api/helpers/upload | Cualquier administrador con sesión iniciada, o un estudiante | Sube un archivo al bucket de archivos multimedia y responde con sus direcciones |
Envía multipart/form-data con el archivo en file, hasta 150 MB, y opcionalmente path (la carpeta, uploads por defecto), for (un tamaño de imagen predefinido) y type (video para omitir el procesamiento de imágenes). Las imágenes se redimensionan en varias versiones; los videos (mp4, webm, mov, m4v) se guardan tal cual. Necesita la configuración del bucket de Almacenamiento multimedia.
La ruta necesita un token de administrador o de estudiante, comprobado antes de leer el archivo. path debe ser una de las carpetas indicadas en back-end/src/modules/helpers/upload/upload-folders.constants.ts; cualquier otra responde 400. Un administrador puede subir a uploads, admins/profile, admins/profiles, users/profiles, blog, categories, courses, instructors, messages y ai-chat. Un estudiante solo puede subir a messages, para las imágenes que adjunta a una conversación. Una pantalla nueva que suba a una carpeta propia necesita añadir esa carpeta a la lista.
curl -X POST http://localhost:8000/api/helpers/upload \
-H "Authorization: Bearer <access_token>" \
-F "file=@cover.jpg" -F "path=courses"Notificaciones, búsqueda y estadísticas
| Método | Ruta | Quién puede llamarla | Qué hace |
|---|---|---|---|
GET | /api/notifications | Cualquier administrador con sesión iniciada | Las notificaciones del administrador con sesión iniciada y el número de no leídas |
PATCH | /api/notifications/read-all | Cualquier administrador con sesión iniciada | Marca todas como leídas y responde con todo el feed |
PATCH | /api/notifications/:id/read | Cualquier administrador con sesión iniciada | Marca una como leída y responde con todo el feed |
DELETE | /api/notifications/:id | Cualquier administrador con sesión iniciada | Elimina una y responde con todo el feed |
GET | /api/search | Cualquier administrador con sesión iniciada | Búsqueda global (q, limit por tipo). Solo se buscan los tipos que permiten los permisos del administrador. |
GET | /api/statistics/trends | courses.view | Las cifras de cada tarjeta de estadísticas, en una sola llamada |
GET | /api/statistics/overview | courses.view | El resumen de la página de inicio del panel, sobre days, con limit filas por lista |
Un administrador solo lee y cambia sus propias notificaciones: las rutas toman al administrador del token. La API escribe una por cada uno de estos eventos, para cada administrador que tenga el permiso que necesita la pantalla enlazada:
| Tipo | Cuándo | Quién lo recibe |
|---|---|---|
enrollment_created | Un estudiante recibe una plaza, por una compra, un curso gratuito o el personal | enrollments.view |
course_completed | Un estudiante termina un curso | enrollments.view |
course_review_submitted | Un estudiante deja una reseña, o edita una que espera aprobación | reviews.view |
course_published | Se publica un curso | courses.view |
student_registered | Un estudiante crea una cuenta | students.view |
Una cuenta de administrador vinculada a un instructor solo recibe avisos de los cursos de ese instructor, y no de los registros nuevos. Cada una se envía además por el socket /notifications en cuanto se guarda.
Clases en vivo
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Las rutas de las clases en vivo: la programación de sesiones y los tokens de acceso que reciben los estudiantes y los anfitriones para una sala de Jitsi Meet.
Certificados
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Las rutas de certificados: cómo solicita un estudiante uno para un curso terminado, y la dirección pública de verificación.
Asistente de IA
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Las rutas del asistente de IA: la transmisión de una respuesta, la lista de modelos y las sesiones de chat guardadas.
Historial de chat del asistente
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Guardar, listar y renombrar las conversaciones del asistente.
Servidor MCP
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
El módulo MCP que ofrece los datos del panel como herramientas para el asistente.
Rutas del modo demostración
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Las rutas que usa una demostración pública: el interruptor de la demostración y las cuentas por visitante.
Pasarelas de pago personalizadas
Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.
Cómo está construida la capa de pagos: las interfaces de pasarela y de webhook, el webhook del simulador y cómo añadir un procesador.