Referencia API

URL base para todos los endpoints: /api/* (backend-js, puerto 3001 en desarrollo).

Todos los endpoints autenticados requieren cabecera Authorization: Bearer <access_token>, salvo donde se indique lo contrario. Los errores siempre devuelven { "error": "message string" }.

[!NOTE] Las formas de request y response se verificaron desde los DTOs, tipos de repository y tipos del cliente frontend. Los defaults de paginacion y respuestas de endpoints solo-admin marcados como Needs verification no estan cubiertos por clientes frontend.

Formato de respuesta de error

Todos los endpoints devuelven errores estructurados:

{ "error": "Human-readable error message" }

Codigos HTTP usados: 400 (validacion), 401 (no autenticado), 403 (rol prohibido), 404 (no encontrado), 409 (conflicto), 500 (error de servidor).

Endpoints de auth

POST /api/auth/login

Publico. Autentica al usuario, emite access token y define la cookie refresh token.

Request body

{ "email": "user@example.com", "password": "secret" }

Response 200

{
  "user": {
    "id": 1,
    "name": "Maria Garcia",
    "email": "user@example.com",
    "role": "distributor",
    "is_active": true
  },
  "access_token": "<JWT>"
}

Define Set-Cookie: refresh_token=...; HttpOnly; SameSite=Lax (dev) / SameSite=None; Secure (prod).


POST /api/auth/refresh

Usa la cookie refresh token. Rota el token y emite un access token nuevo.

Request: sin body, la cookie se envia automaticamente.

Response 200

{ "access_token": "<new JWT>" }

Define una cookie refresh_token nueva. El token anterior se revoca.


POST /api/auth/logout

Revoca el refresh token actual y borra la cookie.

Request: sin body.

Response 200

{ "message": "Logged out" }

GET /api/auth/me

Devuelve el perfil del usuario autenticado. Requiere Bearer token.

Response 200

{
  "id": 1,
  "name": "Maria Garcia",
  "email": "user@example.com",
  "role": "distributor",
  "is_active": true,
  "created_at": "2025-01-15T10:30:00.000Z"
}

POST /api/auth/forgotPassword

Publico. Dispara un email de reset de password. Siempre devuelve exito para evitar enumeracion de emails.

Request body

{ "email": "user@example.com" }

Response 200

{ "message": "If that email is registered, a reset link has been sent." }

PATCH /api/auth/changePwd

Endpoint publico basado en token. Tiene dos modos segun el body.

Modo 1 - solo verificar token (sin new_password):

{ "reset_pwd_token": "<token>" }

Response 200: { "valid": true }

Modo 2 - definir password nuevo:

{ "reset_pwd_token": "<token>", "new_password": "newSecret123" }

Response 200: { "message": "Password changed successfully" }

new_password debe tener al menos 6 caracteres. El token se revoca tras usarlo.


POST /api/auth/activateAccount

Basado en token. Activa una cuenta recien creada y define su password.

Request: ?token=<activate_account_token> (query param) - Needs verification sobre la division exacta entre body y query param.


Endpoints de usuarios (solo admin)

Todos los endpoints de este grupo requieren role: admin.

POST /api/users/create

Crea un usuario nuevo y envia un email de activacion.

Request body

{ "name": "Jon Doe", "email": "jon@example.com", "role": "distributor" }

role debe ser "admin" o "distributor". El usuario se crea inactivo; el email de activacion se envia al email indicado.

Response 201 - Needs verification para la forma exacta; se espera el objeto de usuario creado.


GET /api/users/list

Query params

ParamTipoDefaultDescripcion
pagenumber1Numero de pagina
limitnumber20Maximo 100
role"admin" | "distributor"-Filtrar por rol
is_active"true" | "false"-Filtrar por estado activo

Response 200 - Needs verification para la forma exacta del envelope de paginacion.


GET /api/users/getById?id=<number>

Response 200 - objeto usuario. 404 si no existe.


PATCH /api/users/update

Request body - Needs verification sobre campos permitidos; esperado { name?, email?, role?, is_active? }.


DELETE /api/users/remove?id=<number>

Elimina usuario. Un usuario no puede eliminarse a si mismo.

Response 200 o 403 si intenta autoeliminarse.


PATCH /api/users/changeMyPwd

Cualquier rol autenticado. Cambia la password propia.

Request body

{ "current_password": "oldSecret", "new_password": "newSecret123" }

Response 200

{ "message": "Password updated successfully" }

Endpoints de paquetes

POST /api/packages/create - admin

Crea un paquete, geocodifica la direccion, genera un tracking token y envia un email de tracking.

Request body

{
  "packageInfo": {
    "recipient_name": "Ane Etxeberria",
    "recipient_email": "ane@example.com",
    "assigned_to": null,
    "created_by": 1,
    "status": "pending",
    "weight_kg": 2.5,
    "description": "Fragile"
  },
  "address_info": {
    "street": "Kale Nagusia 12",
    "city": "Tolosa",
    "postal_code": "20400"
  }
}

assigned_to puede ser null (sin asignar) o un ID de usuario valido. description es opcional.

Response 201 - Needs verification para la forma exacta del paquete.


GET /api/packages/list - admin

Query params - Needs verification para el set completo de filtros y envelope de paginacion.


GET /api/packages/getById?id=<number> - admin

Response 200 - PackageWithAddress:

{
  "id": 42,
  "tracking_code": "PAK-20260001",
  "recipient_name": "Ane Etxeberria",
  "recipient_email": "ane@example.com",
  "weight_kg": 2.5,
  "description": "Fragile",
  "status": "pending",
  "estimated_delivery": "2026-05-01",
  "address_id": 7,
  "assigned_to": null,
  "created_by": 1,
  "created_at": "2026-04-26T10:00:00.000Z",
  "updated_at": "2026-04-26T10:00:00.000Z",
  "street": "Kale Nagusia 12",
  "city": "Tolosa",
  "postal_code": "20400",
  "latitude": 43.1298,
  "longitude": -2.0773,
  "country": "Espana"
}

GET /api/packages/getMyPackages - distributor

Devuelve todos los paquetes asignados al repartidor autenticado.

Response 200 - array de PackageWithAddress.


PATCH /api/packages/updateStatus - distributor

Actualiza el estado de uno o varios paquetes. Debe enviarse exactamente uno de package_id o package_ids.

Request body (individual)

{ "package_id": 42, "new_status": "in_transit" }

Request body (batch)

{ "package_ids": [42, 43, 44], "new_status": "delivered" }

new_status debe ser un estado valido: "pending" | "assigned" | "in_transit" | "delivered" | "undelivered" | "failed".

Response 200 - un PackageWithAddress (actualizacion individual) o PackageWithAddress[] (batch).

Dispara insercion de log de estado y efectos secundarios de email (ver Modelo de dominio).


PATCH /api/packages/update?id=<number> - admin

Actualiza informacion del paquete y direccion. Needs verification para campos permitidos.


DELETE /api/packages/delete?id=<number> - admin

Response 200 - Needs verification.


GET /api/packages/getDailySummary - admin

Devuelve un conteo de paquetes por estado para hoy.

Response 200 - Needs verification para la forma exacta; esperado { pending: n, assigned: n, ... }.


Endpoints de rutas y paradas

POST /api/routes/create - admin

Crea una ruta de entrega optimizada para un repartidor en una fecha dada.

Request body

{ "user_id": 3, "date": "2026-05-02", "package_ids": [10, 11, 12] }
  • date debe estar en formato YYYY-MM-DD y ser al menos manana.
  • package_ids no puede estar vacio, no debe contener duplicados y todos deben ser IDs de paquete validos.

Response 200 - Needs verification para la forma exacta del envelope ruta+paradas.


GET /api/routes/getByUserAndDate - admin

Query params: user_id, date - Needs verification.


GET /api/routes/getMyDaily - distributor

Devuelve la ruta y paradas de hoy para el repartidor autenticado.

Response 200

{
  "route": { "id": 5, "route_date": "2026-04-26", "status": "in_progress" },
  "stops": [
    {
      "id": 21,
      "stop_order": 1,
      "estimated_arrival": "09:30:00",
      "actual_arrival": "09:28:00",
      "package": {
        "id": 42,
        "recipient_name": "Ane Etxeberria",
        "status": "delivered",
        "address": {
          "street": "Kale Nagusia 12",
          "city": "Tolosa",
          "lat": 43.1298,
          "lng": -2.0773
        }
      }
    }
  ]
}

PATCH /api/routes/updateStatus/:id - admin o distributor (acotado)

Request body

{ "status": "in_progress" }

status debe ser "in_progress" o "completed".

Response 200

{ "message": "Route status updated" }

GET /api/routes/continueFromPast - distributor

Comprueba si el repartidor tiene una ruta pasada con paradas pendientes.

Response 200

{
  "pending": {
    "route_id": 3,
    "route_date": "2026-04-25",
    "status": "in_progress",
    "pending_count": 2,
    "route_count": 5
  }
}

pending es null si no existe ruta pasada pendiente.


POST /api/routes/continueFromPast - distributor

Migra paradas pendientes de la ultima ruta pasada pendiente a la ruta de hoy.

Request: sin body.

Response 200

{
  "route_id": 6,
  "new_route_date": "2026-04-26",
  "migrated_stops": 2
}

PATCH /api/stops/reorder - admin

Reordena paradas dentro de una ruta. Needs verification para la forma del body.


PATCH /api/stops/updateArrival - distributor

Registra la hora real de llegada a una parada.

Request body

{ "stop_id": 21 }

Response 200

{
  "id": 21,
  "route_id": 5,
  "package_id": 42,
  "stop_order": 1,
  "estimated_arrival": "09:30:00",
  "actual_arrival": "09:28:00"
}

Endpoints de logs

GET /api/logs/listByPackage - admin

Query params: packageId (required), page, limit.

Response 200

{
  "logs": [
    {
      "id": 1,
      "packageId": 42,
      "oldStatus": "assigned",
      "newStatus": "in_transit",
      "changedBy": 3,
      "notes": null,
      "changedAt": "2026-04-26T09:00:00.000Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 20
}

GET /api/logs/listAll - admin

Lista todos los logs de estado de todos los paquetes. Needs verification para filtros y envelope de paginacion.


Endpoint de tracking (publico)

GET /api/tracking/:trackingToken

Publico. No requiere auth. El token es una cadena hex de 32 bytes.

Response 200

{
  "tracking_code": "PAK-20260001",
  "recipient_name": "Ane Etxeberria",
  "status": "in_transit",
  "estimated_delivery": "2026-05-01",
  "address": {
    "street": "Kale Nagusia 12",
    "city": "Tolosa",
    "postal_code": "20400"
  },
  "last_update": "2026-04-26T09:00:00.000Z"
}

El token caduca tras TRACKING_EXPIRES_DAYS dias (default 30). Devuelve 404 si el token es desconocido o ha caducado.