API Reference
The pakAG backend is a Next.js 15 App Router API. All endpoints live under /api/* and run on port 3001 in development.
Base URL
http://localhost:3001/api (development)
https://tolosaerronka.es/api (production)Authentication
All endpoints require Authorization: Bearer <access_token> except where noted as Auth required: No.
Obtain an access token via POST /api/auth/login. Tokens expire after 15 minutes (default). Refresh silently with POST /api/auth/refresh, which rotates the refresh token cookie.
Roles: admin | distributor
Error format
Every error response uses a consistent envelope:
{ "error": "Human-readable error message" }HTTP status codes:
| Code | Meaning |
|---|---|
| 400 | Validation error |
| 401 | Unauthenticated (missing or invalid token) |
| 403 | Forbidden (wrong role, or resource not owned) |
| 404 | Resource not found |
| 409 | Conflict (duplicate, FK constraint) |
| 500 | Internal server error |
Pagination
Paginated endpoints accept page (default 1) and limit (default 20, max 100) as query parameters and return:
{
"items": [...],
"total": 42,
"page": 1,
"limit": 20
}The field name for the array varies per resource (users, packages, logs).
Resources
| Resource | Base path | Description |
|---|---|---|
| Auth | /api/auth | Login, logout, token refresh, password reset, account activation |
| Users | /api/users | User CRUD (admin), change own password (any role) |
| Packages | /api/packages | Package lifecycle — create, list, update, delete, status transitions |
| Routes | /api/routes | Optimized delivery route creation and management |
| Stops | /api/stops | Reorder stops, record arrival times |
| Logs | /api/logs | Package status-change audit log |
| Tracking | /api/tracking | Public package tracking by token |
Package status lifecycle
pending → assigned → in_transit → delivered
↘ undelivered
↘ failedEach transition triggers a status log entry and a tracking email to the recipient. See PATCH /api/packages/updateStatus for allowed transitions per role.
Auth token flow
POST /api/auth/login
→ body: { user, access_token }
→ cookie: refresh_token (HttpOnly)
Authorization: Bearer <access_token> ← every request
POST /api/auth/refresh ← when access token expires
→ body: { access_token }
→ cookie: new refresh_token (old one revoked)
POST /api/auth/logout
→ refresh token revoked, cookie cleared