Garantizar que todos los endpoints del proyecto, sin importar qué equipo los construya, tengan la misma forma, el mismo comportamiento de errores y la misma semántica HTTP.
Lectura u operación exitosa con cuerpo de respuesta
201 Created
Recurso creado (incluye Location o el recurso en el body)
204 No Content
Operación exitosa sin cuerpo (ej. DELETE)
400 Bad Request
Solicitud mal formada (JSON inválido, parámetros incorrectos)
401 Unauthorized
No autenticado
403 Forbidden
Autenticado pero sin permiso
404 Not Found
Recurso no existe
409 Conflict
Conflicto de estado (ej. duplicado)
422 Unprocessable Entity
Validación de datos fallida (estándar en Laravel)
429 Too Many Requests
Rate limit excedido
500 Internal Server Error
Error no controlado del servidor
Regla P0/OBLIGATORIO: nunca devolver 200 OK con un error dentro del body ({"error": true} con status 200). El código HTTP siempre refleja el resultado real.
Este es el formato mínimo que el proyecto exige. LengthAwarePaginator de Laravel (->paginate()), envuelto en una ResourceCollection, produce por defecto una estructura más amplia (meta con from, to, last_page, path, links[]; links con first, last). Se acepta el default de Laravel siempre que incluya, como mínimo, data, meta.current_page, meta.per_page, meta.total y links.next/links.prev. Si se personaliza, el formato debe ser idéntico en todos los endpoints paginados.
Response de error (formato único en todo el proyecto)
Todo error de validación devuelve 422 con el formato de la sección 5 — P1/OBLIGATORIO. En Laravel, esto ya es el comportamiento por defecto de un FormRequest; se estandariza el formato de salida mediante el manejador de excepciones central.
Los errores 500 nunca exponen el stack trace ni mensajes internos en producción; en desarrollo sí, para depuración — P0/OBLIGATORIO.
Autenticación vía Laravel Sanctum (tokens, adecuado para SPA/API separada de este proyecto) — RECOMENDADO como default; OAuth2 completo (Passport) es AVANZADO y solo si se justifica.
Todo endpoint que no sea explícitamente público requiere autenticación (auth:sanctum) — P0/OBLIGATORIO.
La autorización de “quién puede hacer qué” se resuelve con Policies (Doc. 02), no con if dispersos en el controlador — P1/OBLIGATORIO.
Se versiona desde el día uno con /api/v1/ aunque solo exista una versión — P1/OBLIGATORIO. Evita romper contratos con el frontend cuando el proyecto crezca.
Un breaking change de contrato (quitar/renombrar un campo, cambiar un tipo) requiere v2, no se modifica v1 en producción — P2/RECOMENDADO (AVANZADO en la práctica, dado el alcance del proyecto, pero la regla de versionar desde el inicio sí es obligatoria).
PUT y DELETE deben ser idempotentes: llamarlos dos veces con los mismos datos produce el mismo estado final — P1/OBLIGATORIO.
Operaciones críticas no idempotentes por naturaleza (ej. procesar un pago) deben prevenir duplicados con una clave de idempotencia o validación de estado previo — P2/RECOMENDADO (AVANZADO en implementación con Idempotency-Key header).
Cada endpoint se documenta (mínimo: método, ruta, parámetros, ejemplo de request/response, códigos de error posibles) en docs/api/ o vía anotaciones OpenAPI (l5-swagger) — P1/OBLIGATORIO desde Fase 3 (ver Doc. 16).