HomeInicio

Logistics API & Integration

API de Logística e Integración

Comprehensive guide to consume the logistics system services

Guía completa para consumir los servicios del sistema logístico

📋 CRM API Docs 📋 Docs API CRM

Quick Reference

Referencia Rápida

Welcome to the Logistics API. This system allows you to manage orders, products, and geographic data using standard HTTP requests.

Bienvenido a la API de Logística. Este sistema te permite gestionar pedidos, productos y datos geográficos usando peticiones HTTP estándar.

✨ Key Concepts

✨ Conceptos Clave

  • Base URL: /api (relative to your installation)
  • Auth: JWT Bearer Token required for write operations.
  • Response Format: All responses are JSON wrapped in a standard envelope.
  • Dates: Format YYYY-MM-DD HH:MM:SS unless otherwise specified.
  • URL Base: /api (relativo a tu instalación)
  • Auth: Token Bearer JWT requerido para operaciones de escritura.
  • Formato Respuesta: Todas las respuestas son JSON envueltas en un sobre estándar.
  • Fechas: Formato YYYY-MM-DD HH:MM:SS a menos que se especifique lo contrario.

Standard Response Envelope

Sobre de Respuesta Estándar

Every API response follows this consistent JSON structure:

Toda respuesta de la API sigue esta estructura JSON consistente:

{
    "success": true,           // boolean: did the request succeed?
    "message": "Operation...", // string: human-readable message
    "data": { ... }            // object/array: the requested payload
}

Error Response Example

Ejemplo de Respuesta de Error

{
    "success": false,
    "message": "Invalid credentials",
    "error_code": 401          // optional: numeric error code
}

Pagination

Paginación

Endpoints that return lists (Orders, Products) support pagination via query parameters.

Los endpoints que retornan listas (Pedidos, Productos) soportan paginación vía parámetros GET.

ParameterTypeDefaultDescription
pageinteger1Current page number
limitinteger20Items per page
ParámetroTipoDefectoDescripción
pageentero1Número de página actual
limitentero20Elementos por página

Paginated Response

Respuesta Paginada

{
    "success": true,
    "data": [ ... ],
    "pagination": {
        "total": 150,
        "page": 1,
        "limit": 20,
        "total_pages": 8
    }
}

Get Order States

Obtener Estados de Pedidos

Retrieve all available order states programmatically.

Obtener todos los estados de pedidos disponibles de forma programática.

GET /api/pedidos/estados 🌐 PublicPúblico

Example Request

Ejemplo de Petición

GET /api/pedidos/estados

Response 200 OK

Respuesta 200 OK

{
    "success": true,
    "data": [
        {"id": 1, "nombre_estado": "En bodega"},
        {"id": 2, "nombre_estado": "En ruta o proceso"},
        {"id": 3, "nombre_estado": "Entregado"},
        {"id": 4, "nombre_estado": "Reprogramado"},
        {"id": 5, "nombre_estado": "Domicilio cerrado"},
        {"id": 6, "nombre_estado": "No hay quien reciba en domicilio"},
        {"id": 7, "nombre_estado": "Devuelto"},
        {"id": 8, "nombre_estado": "Domicilio no encontrado"},
        {"id": 9, "nombre_estado": "Rechazado"},
        {"id": 10, "nombre_estado": "No puede pagar recaudo"},
        {"id": 11, "nombre_estado": "Pendiente recolección"},
        {"id": 12, "nombre_estado": "Recolectado por mensajería"},
        {"id": 13, "nombre_estado": "Traslado a punto de distribución"},
        {"id": 14, "nombre_estado": "Entregado-liquidado"},
        {"id": 15, "nombre_estado": "Devuelto a bodega"},
        {"id": 16, "nombre_estado": "Incidencia"},
        {"id": 17, "nombre_estado": "Cancelado"},
        {"id": 18, "nombre_estado": "Correo"},
        {"id": 19, "nombre_estado": "Disponible para retirar en Agencia"}
    ]
}
💡 Use Cases 💡 Casos de Uso
  • Populate status dropdown filters
  • Build dynamic order management UIs
  • Validate status IDs before updates
  • Poblar filtros dropdown de estados
  • Construir UIs dinámicas de gestión de pedidos
  • Validar IDs de estado antes de actualizar

Order Status Reference

Referencia de Estados

Use these IDs when filtering or updating order statuses.

Usa estos IDs al filtrar o actualizar estados de pedidos.

ID Status NameNombre Estado DescriptionDescripción
1En bodegaInitial status, order received at warehouse.Estado inicial, pedido recibido en bodega.
2En ruta o procesoOrder is being delivered.El pedido está en camino.
3EntregadoOrder successfully delivered.Pedido entregado exitosamente.
4ReprogramadoDelivery rescheduled for another day/time.Entrega reprogramada para otro día/hora.
5Domicilio cerradoDelivery failed: location closed.Falló entrega: lugar cerrado.
6No hay quien recibaDelivery failed: no recipient available.Falló entrega: nadie para recibir.
7DevueltoOrder returned to warehouse.Pedido devuelto a bodega.
8Domicilio no encontradoAddress could not be located.No se encontró la dirección.
9RechazadoCustomer rejected the order.Cliente rechazó el pedido.
10No puede pagar recaudoCustomer unable to pay on delivery.Cliente no pudo pagar al recibir.
11Pendiente recolecciónWaiting for messenger pick up.Esperando recolección por mensajería.
12RecolectadoPicked up by the messenger service.Recolectado por el servicio de mensajería.
13TrasladoBeing moved to distribution point.En traslado hacia punto de distribución.
14Entregado-liquidadoOrder delivered and payment settled.Pedido entregado y pago liquidado.
15Devuelto a bodegaDelivered back to main warehouse.Entregado de vuelta en bodega.
16IncidenciaGeneral delivery issue.Incidencia general en la entrega.
17CanceladoOrder cancelled.Pedido cancelado.
18CorreoOrder dispatched via postal mail, delivery pending confirmation.Pedido despachado por correo postal, entrega pendiente de confirmación.
19Disponible para retirar en AgenciaPackage available for pickup at the agency branch.Paquete disponible para retiro en agencia.

Authentication

Autenticación

To perform write operations (create orders, products, etc.), you must obtain a JWT token.

Para realizar operaciones de escritura (crear pedidos, productos, etc.), debes obtener un token JWT.

Role Access & Capabilities: Accesos y Capacidades por Rol:
  • Role: Client
    Use this role for Order Management: Create new orders, manage massive shipments, and control inventory.
    Usa este rol para Gestión de Pedidos: Crear nuevos pedidos, administrar envíos masivos y controlar inventario.
  • Role: Provider
    Use this role for Tracking & Visualization: View order history and real-time delivery status.
    Usa este rol para Seguimiento y Visualización: Ver historial de pedidos y estado de entrega en tiempo real.

1. Get Token

1. Obtener Token

POST /api/auth/login 🔓 PublicPúblico
Request Body
Cuerpo de la Petición
FieldTypeRequiredDescription
emailstring✅ YesRegistered user email
passwordstring✅ YesUser password
CampoTipoReq.Descripción
emailstring✅ SíEmail del usuario registrado
passwordstring✅ SíContraseña del usuario
Example Request
Ejemplo de Petición
curl -X POST "http://localhost/paqueteriacz/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@example.com", "password":"secure_password"}'
Response 200 OK
Respuesta 200 OK
{
    "success": true,
    "message": "Login exitoso",
    "data": {
        "token": "eyJ0e... (your_token_here) ... "
    }
}

2. Use Token

2. Usar el Token

Include the token in the Authorization header for subsequent requests.

Incluye el token en el encabezado Authorization para las siguientes peticiones.

Authorization: Bearer <YOUR_TOKEN>

List & View

Listar y Ver

List Orders

Listar Pedidos

GET /api/pedidos/listar 🔐 AuthenticatedAutenticado

Retrieve a list of orders with advanced filtering and pagination. Use these parameters to refine your results.

Obtén una lista de pedidos con filtrado avanzado y paginación. Usa estos parámetros para refinar tus resultados.

Query Parameters (Filters)
Parámetros de Consulta (Filtros)
ParameterParámetro TypeTipo DescriptionDescripción ExampleEjemplo
pageintPage number (default: 1)Número de página (defecto: 1)1
limitintResults per page (max: 100)Resultados por página (máx: 100)20
numero_ordenstringOrder numberNúmero de orden externo88002
numero_clienteintClient IDID del cliente10
Sample Request
Ejemplo de Uso
GET /api/pedidos/listar?numero_orden=88002&numero_cliente=10

Get Single Order

Ver Pedido

GET /api/pedidos/ver?id=100 🔐 AuthenticatedAutenticado

Returns full details of a specific order by Internal ID.

Create Order

Crear Pedido

Create a new delivery order. The system automatically validates stock, calculates pricing, and enforces security rules based on user role.

Crea un nuevo pedido de entrega. El sistema valida automáticamente el stock, calcula precios y aplica reglas de seguridad según el rol del usuario.

⚠️ Strict Required Fields: ⚠️ Campos estrictos (obligatorios):

These fields are REQUIRED/STRICT. If any is missing, empty, or incorrect, the order WILL NOT be created and an HTTP 400 error will be returned with field-specific details.

Estos campos son REQUIRED/STRICT. Si falta alguno o viene vacío/incorrecto, el pedido NO se crea y se retorna HTTP 400 con detalle por campo.

📮 Auto-fill from Postal Code: 📮 Autocompletado desde Código Postal:

If you send codigo_postal, the system will automatically resolve and fill id_pais, id_departamento, id_municipio and id_barrio from the postal code database — these fields become optional when the CP is recognized.

Si envías codigo_postal, el sistema resolverá y completará automáticamente id_pais, id_departamento, id_municipio e id_barrio desde la base de códigos postales. Estos campos se vuelven opcionales cuando el CP es reconocido.

POST /api/pedidos/crear 🔐 AuthenticatedAutenticado 👤 Role: ClientRol: Cliente

🔑 Required Fields (Strict)

🔑 Campos Obligatorios (Estrictos)

FieldTypeValidationDescription
numero_ordeninteger/stringSTRICTExternal order ID
destinatariostringSTRICTRecipient's full name
producto_idarraySTRICT if requiere_productos is 1 or omittedArray of product objects/IDs. Optional when "requiere_productos": 0 is sent in the body.
id_clienteintegerSTRICT, existsClient ID owner
id_proveedorintegerSTRICT, existsMessenger/Provider ID assigned
telefonostringSTRICTContact phone
direccionstringSTRICTFull delivery address
comentariostringSTRICTDelivery notes
precio_total_localdecimalSTRICT, > 0Total local price
es_combointegerSTRICT (0 or 1)1 for combo, 0 for standard
fecha_entregastringSTRICT, format YYYY-MM-DDEstimated delivery date (e.g. "2026-03-15")
CampoTipoValidaciónDescripción
numero_ordeninteger/stringESTRICTOID externo del pedido
destinatariostringESTRICTONombre del destinatario
producto_idarrayESTRICTO si requiere_productos es 1 u omitidoArray de productos (objetos o IDs). Opcional cuando se envía "requiere_productos": 0 en el body.
id_clienteenteroESTRICTO, existeID del cliente dueño
id_proveedorenteroESTRICTO, existeID del proveedor de mensajería asignado
telefonostringESTRICTOTeléfono de contacto
direccionstringESTRICTODirección completa
comentariostringESTRICTONotas de entrega
precio_total_localdecimalESTRICTO, > 0Precio total local
es_comboenteroESTRICTO (0 o 1)1 si es combo, 0 si estándar
fecha_entregastringESTRICTO, formato YYYY-MM-DDFecha estimada de entrega (ej. "2026-03-15")
🚩 Body Flag: requiere_productos

Works exactly like es_combo — it’s a field you send in the JSON body:

  • Omitted or 1 → Products are required. Omitting productos/producto_id returns HTTP 422.
  • 0 → Products are optional. The order is created without product items.
  • Any other value returns a validation error.
{ "requiere_productos": 0 }
🚩 Bandera en el Body: requiere_productos

Funciona igual que es_combo — es un campo que envías en el body JSON:

  • Omitido o 1 → Productos obligatorios. Omitir productos/producto_id retorna HTTP 422.
  • 0 → Productos opcionales. El pedido se crea sin items de productos.
  • Cualquier otro valor retorna error de validación.
{ "requiere_productos": 0 }

Bulk Import (Async)

Importación Masiva (Async)

Import multiple orders efficiently. Use auto_enqueue=true to process in background.

Importa múltiples pedidos eficientemente. Usa auto_enqueue=true para procesar en segundo plano.

POST /api/pedidos/multiple?auto_enqueue=true 🔐 AuthenticatedAutenticado 👤 Role: ClientRol: Cliente

📋 Optional Details (Automatic)

📋 Detalles Opcionales (Automáticos)

FieldTypeDefaultDescription
coordenadasstringnullGPS format: "lat,long" (e.g. "14.6349,-90.5069")
latitudfloatnullLatitude (alternative to coordenadas)
longitudfloatnullLongitude (alternative to coordenadas)
id_barriointegernullNeighborhood/District ID (if known)
CampoTipoDefectoDescripción
coordenadasstringnullFormato GPS: "lat,long" (ej. "14.6349,-90.5069")
latitudfloatnullLatitud (alternativa a coordenadas)
longitudfloatnullLongitud (alternativa a coordenadas)
id_barrioenteronullID del barrio/distrito (si se conoce)

🌍 Optional Fields - Geographic Auto-fill from CP

🌍 Campos Opcionales - Geográficos Auto desde CP

FieldTypeDescription
codigo_postalstringPostal code. When provided, auto-fills country, dept, municipality and neighborhood.
id_pais or paisintegerCountry ID. Optional if codigo_postal is recognized.
id_departamento or departamentointegerState/Department ID. Optional if codigo_postal is recognized.
id_municipio or municipiointegerCity/Municipality ID. Optional if codigo_postal is recognized.
id_barrio or barriointegerNeighborhood/District ID. Optional, auto-filled from CP if available.
zonastringZone name. Optional.
code_city HLExpress string City code sent as city_dane_code to HLExpress. Takes priority over codigo_postal when dispatching to HLExpress. Example: 100075918
CampoTipoDescripción
codigo_postalstringCódigo postal. Al enviarlo, el sistema auto-rellena país, depto, municipio y barrio.
id_pais o paisenteroID del país. Opcional si el codigo_postal es reconocido.
id_departamento o departamentoenteroID del departamento. Opcional si el codigo_postal es reconocido.
id_municipio o municipioenteroID del municipio. Opcional si el codigo_postal es reconocido.
id_barrio o barrioenteroID del barrio. Opcional, se auto-rellena desde CP si está disponible.
zonastringNombre de la zona. Opcional.
code_city HLExpress string Código de ciudad enviado como city_dane_code a HLExpress. Tiene prioridad sobre codigo_postal al despachar a HLExpress. Ej: 100075918

📍 Optional Fields - Special Address For orders without postal code

📍 Campos Opcionales - Dirección Especial Para pedidos sin código postal

When to use: Use these fields when the order destination does not have a registered postal code in the system. These are text-based fields for special orders (e.g. international clients like Panama). If codigo_postal is provided, these fields are stored but not displayed in views.
Cuándo usarlos: Usa estos campos cuando el destino del pedido no tiene un código postal registrado en el sistema. Son campos de texto libre para pedidos especiales (ej. clientes internacionales como Panamá). Si se envía codigo_postal, estos campos se guardan pero no se muestran en las vistas.
FieldTypeMax LengthDescription
departmentNamestring150Department/Province name (text)
municipalitiesNamestring150Municipality/City name (text)
postalCodestring20Postal code (text, not homologated)
Locationstring255Location reference (landmarks, plaza, etc.)
betweenStreetsstring255Cross streets reference
CampoTipoLargo Máx.Descripción
departmentNamestring150Nombre del departamento/provincia (texto)
municipalitiesNamestring150Nombre del municipio/ciudad (texto)
postalCodestring20Código postal (texto, no homologado)
Locationstring255Referencia de ubicación (punto de referencia, plaza, etc.)
betweenStreetsstring255Referencia de entre calles

👥 Optional Fields - Assignments

👥 Campos Opcionales - Asignaciones

FieldTypeDefaultDescription
id_estadointeger1Order status (see Status Reference)
id_vendedorintegernullAssigned delivery person
id_proveedorinteger✅ YesMessenger/Provider ID assigned to the order
id_clienteintegernullClient ID
id_monedaintegernullCurrency ID (auto-detected from provider's country if not provided)
requiere_productosinteger1Product requirement flag: 1 = required (default), 0 = optional (order created without product items).
CampoTipoDefectoDescripción
id_estadoentero1Estado del pedido (ver Referencia de Estados)
id_vendedorenteronullRepartidor asignado
id_proveedorentero✅ SíID del usuario de mensajería (Proveedor) asignado
id_clienteenteronullID del cliente
id_monedaenteronullID de la moneda (auto-detectada del país del proveedor si no se envía)
requiere_productosentero1Bandera de productos: 1 = requeridos (defecto), 0 = opcionales (pedido se crea sin ítems de producto).

💰 Optional Fields - Pricing

💰 Campos Opcionales - Precios

FieldTypeAuto-calculatedDescription
precio_total_localdecimalNoTotal price in local currency
precio_total_usddecimalYes*Total price in USD (auto-calc if local + currency provided)
tasa_conversion_usddecimalYes*Exchange rate used (auto-fetched from currency)
es_combobooleanYes*Whether it's a combo (auto-detected from product)
CampoTipoAuto-calculadoDescripción
precio_total_localdecimalNoPrecio total en moneda local
precio_total_usddecimalSí*Precio total en USD (auto-calc si local + moneda)
tasa_conversion_usddecimalSí*Tasa de cambio usada (auto desde moneda)
es_combobooleanSí*Si es combo (auto-detectado desde producto)

❌ Error Response (Validation Error)

❌ Respuesta de Error (Falla de Validación)

When strict rules are not met, a 400 Bad Request is returned with a VALIDATION_ERROR message and a fields object mapping each field to its specific error.

Cuando no se cumplen las reglas estrictas, se devuelve 400 Bad Request con el mensaje VALIDATION_ERROR y un objeto fields que detalla el error por cada campo.

{
    "success": false,
    "message": "VALIDATION_ERROR",
    "fields": {
        "numero_orden": "El número de orden ya existe para este cliente.",
        "id_departamento": "El departamento no pertenece al país seleccionado.",
        "telefono": "El campo 'telefono' debe tener al menos 7 caracteres."
    }
}

✅ Automatic Validations

✅ Validaciones Automáticas

  • Geography Hierarchy: Rejects if Department doesn't match Country, or Municipality doesn't match Department.
  • CP Normalization: Postal codes are converted to uppercase and stripped of spaces/dashes before saving.
  • Order Uniqueness: Scoped by id_cliente to prevent collision between different clients' numbering.
  • Stock validation: Ensures sufficient inventory before creating order.
  • Foreign key validation: Verifies that all IDs (vendor, provider, client, currency) exist in database.
  • Jerarquía Geográfica: Rechaza si el Depto no coincide con el País, o el Muni no coincide con el Depto.
  • Normalización de CP: Los códigos postales se convierten a mayúsculas y se limpian de espacios/guiones.
  • Unicidad de Orden: Validada por id_cliente para evitar colisiones entre numeración de distintos clientes.
  • Validación de stock: Asegura inventario suficiente antes de crear.
  • Validación FK: Verifica que todos los IDs (vendedor, proveedor, cliente, moneda) existan en BD.

🔐 Security Rules

🔐 Reglas de Seguridad

Provider Assignment: This field is strict. You must explicitly provide the ID of the user (role Provider) who will handle the delivery.

Asignación de Proveedor: Este campo es estricto. Debes proporcionar explícitamente el ID del usuario (rol Proveedor) que gestionará la entrega.

📝 Example: Minimal Order (auto-fill from postal code)

📝 Ejemplo: Pedido Mínimo (auto-relleno desde código postal)

{
    "numero_orden": 697896,
    "destinatario": "Carlos Mendoza",
    "id_cliente": 9,
    "telefono": "(502) 5555-1234",
    "direccion": "6 Avenida 12-34 Zona 3",
    "comentario": "Dejar con el guardia si no hay nadie.",
    "id_proveedor": 12,
    "zona": "Zona 3 Centro",
    "codigo_postal": "46400",
    "fecha_entrega": "2026-03-15",
    "precio_total_local": 250.75,
    "es_combo": 1,
    "productos": [
        { "producto_id": 49, "cantidad": 10 }
    ]
    // id_pais, id_departamento, id_municipio se auto-rellenan desde el CP
}

🚚 Example: Order with HLExpress city code

🚚 Ejemplo: Pedido con código de ciudad HLExpress

HLExpress: When this order is dispatched to HLExpress, the code_city value is sent as city_dane_code. It takes priority over codigo_postal for this field.
HLExpress: Al despachar este pedido a HLExpress, el valor de code_city se envía como city_dane_code. Tiene prioridad sobre codigo_postal para ese campo.
{
    "numero_orden": 697896,
    "destinatario": "Carlos Mendoza",
    "id_cliente": 9,
    "telefono": "(502) 5555-1234",
    "direccion": "6 Avenida 12-34 Zona 3",
    "comentario": "Dejar con el guardia si no hay nadie.",
    "id_proveedor": 12,
    "codigo_postal": "46400",
    "code_city": "100075918",
    "fecha_entrega": "2026-03-15",
    "precio_total_local": 250.75,
    "es_combo": 1,
    "productos": [
        { "producto_id": 49, "cantidad": 10 }
    ]
}

📝 Example: Special Order (no postal code, custom address fields)

📝 Ejemplo: Pedido Especial (sin código postal, campos de dirección personalizados)

{
    "numero_orden": 697897,
    "destinatario": "Ana Sofia Ramos",
    "id_cliente": 9,
    "telefono": "50761234567",
    "direccion": "Calle 50, Edificio Global Bank, Piso 3",
    "comentario": "Entregar en recepción.",
    "id_proveedor": 12,
    "fecha_entrega": "2026-03-20",
    "precio_total_local": 320.00,
    "es_combo": 0,
    "departmentName": "Panamá",
    "municipalitiesName": "San Miguelito",
    "postalCode": "0801",
    "Location": "Plaza Central, frente al supermercado",
    "betweenStreets": "Entre Calle 5ta y Avenida Balboa",
    "productos": [
        { "producto_id": 49, "cantidad": 5 }
    ]
}

📝 Example: Manual location fields (IDs)

📝 Ejemplo: Campos de ubicación manuales (IDs)

{
    "numero_orden": 697898,
    "destinatario": "Roberto Fuentes",
    "id_cliente": 9,
    "telefono": "(502) 4444-9876",
    "direccion": "18 Calle 2-10 Zona 15",
    "comentario": "Llamar antes de entregar.",
    "id_proveedor": 12,
    "id_pais": 1,
    "id_departamento": 1,
    "id_municipio": 1,
    "zona": "Vista Hermosa",
    "fecha_entrega": "2026-03-20",
    "precio_total_local": 320.00,
    "es_combo": 1,
    "productos": [
        { "producto_id": 49, "cantidad": 5 }
    ]
}

📝 Example: Complete Multi-Product Combo

📝 Ejemplo: Pedido Completo con Múltiples Productos y Combo

{
    "numero_orden": 697898,
    "destinatario": "Roberto Fuentes",
    "id_cliente": 9,
    "telefono": "(502) 3333-5678",
    "direccion": "Diagonal 12 8-55 Zona 10",
    "comentario": "Entregar en horario de oficina.",
    "id_proveedor": 12,
    "zona": "Pradera",
    "codigo_postal": "01010",
    "id_moneda": 2,
    "fecha_entrega": "2026-03-25",
    "es_combo": 1,
    "precio_total_local": 780.50,
    "productos": [
        { "producto_id": 49, "cantidad": 3 },
        { "producto_id": 50, "cantidad": 2 }
    ]
}

📦 Example: Order Without Products (requiere_productos: 0)

📦 Ejemplo: Pedido Sin Productos (requiere_productos: 0)

⚠️ Note: When sending "requiere_productos": 0, omit the productos array entirely. The order is registered without product items.
⚠️ Nota: Al enviar "requiere_productos": 0, omite completamente el array productos. El pedido se registra sin ítems de producto.
{
    "numero_orden": 697900,
    "destinatario": "Maria López",
    "id_cliente": 9,
    "telefono": "50588887777",
    "direccion": "De la Catedral 2 cuadras al lago, Managua",
    "comentario": "Entregar en recepción.",
    "id_proveedor": 12,
    "codigo_postal": "11001",
    "fecha_entrega": "2026-03-20",
    "precio_total_local": 450.00,
    "es_combo": 0,
    "requiere_productos": 0
    // No se incluye el campo "productos" — el pedido se crea sin ítems
}

Bulk Import (Async)

Importación Masiva (Async)

Import multiple orders efficiently. Use auto_enqueue=true to process in background.

Importa múltiples pedidos eficientemente. Usa auto_enqueue=true para procesar en segundo plano.

POST /api/pedidos/multiple?auto_enqueue=true 🔐 AuthenticatedAutenticado

Success Response (202 Accepted)

Respuesta Exitosa (202 Accepted)

{
    "success": true,
    "message": "Proceso iniciado",
    "results": [
        { "numero_orden": 10050, "success": true, "job_queued": true },
        { "numero_orden": 10051, "success": true, "job_queued": true }
    ]
}

Advanced Example: Multiple Products & Combo

Ejemplo Avanzado: Múltiples Productos y Combos

{
    "pedidos": [
        {
            "numero_orden": 697901,
            "destinatario": "Luis Herrera",
            "id_cliente": 9,
            "telefono": "(502) 1111-2222",
            "direccion": "Ruta Nacional 9 Km 45",
            "comentario": "Entregar en recepción.",
            "id_proveedor": 12,
            "codigo_postal": "46400",
            "fecha_entrega": "2026-03-15",
            "precio_total_local": 250.75,
            "es_combo": 1,
            "productos": [
                { "producto_id": 49, "cantidad": 5 },
                { "producto_id": 50, "cantidad": 3 }
            ]
        },
        {
            "numero_orden": 697902,
            "destinatario": "Marta Lopez",
            "id_cliente": 9,
            "telefono": "(502) 3333-4444",
            "direccion": "Colonia El Naranjo Mz. 4",
            "comentario": "Tocar timbre dos veces.",
            "id_proveedor": 12,
            "codigo_postal": "46400",
            "fecha_entrega": "2026-03-22",
            "precio_total_local": 480.00,
            "es_combo": 1,
            "productos": [
                { "producto_id": 49, "cantidad": 2 },
                { "producto_id": 51, "cantidad": 1 }
            ]
        }
    ]
}

Currency Management (Monedas)

Gestión de Monedas

Administrative endpoints to list, create, update and delete currencies.

Endpoints administrativos para listar, crear, actualizar y eliminar monedas.

GET /api/monedas/listar
GET /api/monedas/ver?id=1
POST /api/monedas/crear
POST/PUT /api/monedas/actualizar?id=1
DELETE /api/monedas/eliminar?id=1
Auth: Auth: Requires Bearer token with permissions for currency administration. Requiere Bearer token con permisos de administración de monedas.

Product Management

Gestión de Productos

GET /api/productos/listar 🔓 PublicPúblico

List all available products with current stock.

Listar todos los productos disponibles con stock actual.

Query Parameters
Parámetros de Consulta
ParameterTypeDescription
pageintegerPage number (default 1)
limitintegerItems per page (default 50)
id_clienteintegerFilter by Creator/Client ID
categoria_idintegerFilter by Category ID
marcastringFilter by Brand name (exact match)
skustringFilter by exact SKU
activobooleanFilter by active status (1/0 or true/false)
ParámetroTipoDescripción
pageenteroNúmero de página (defecto 1)
limitenteroItems por página (defecto 50)
id_clienteenteroFiltrar por ID de Cliente/Creador
categoria_identeroFiltrar por ID de Categoría
marcastringFiltrar por Marca (coincidencia exacta)
skustringFiltrar por SKU exacto
activobooleanFiltrar por estado activo (1/0 o true/false)
📝 Usage Examples
📝 Ejemplos de Uso
# 1. List products created by client ID 15
GET /api/productos/listar?id_cliente=15

# 2. List only active products in category 8
GET /api/productos/listar?activo=1&categoria_id=8

# 3. Filter by brand
GET /api/productos/listar?marca=Samsung

# 4. Combined filter with pagination
GET /api/productos/listar?id_cliente=15&activo=1&page=2&limit=10
POST /api/productos/crear 🔐 AuthenticatedAutenticado 👤 Role: ClientRol: Cliente

Create a new product.

Crear un nuevo producto.

Request Body
Cuerpo de la Petición
FieldCampo TypeTipo Req.Req. DescriptionDescripción
nombrestringProduct nameNombre del producto
skustringUnique identifier (SKU)Identificador único (SKU)
descripcionstringProduct descriptionDescripción del producto
precio_usdnumberPrice in USDPrecio en USD
stockintegerInitial stock levelNivel de stock inicial

Product Object Model

Modelo de Objeto Producto

{
    "id": 1,
    "nombre": "Protein Shake",
    "sku": "PROT-SHK-001",
    "precio_usd": "45.00",
    "stock_total": 150,
    "descripcion": "High quality whey protein"
}

Update & Delete

Actualizar y Eliminar

Update Product

Actualizar Producto

POST /api/productos/actualizar 🔐 AuthenticatedAutenticado 👤 Role: ClientRol: Cliente
Note: Use POST with id param or check PHP config for PUT support.
{
    "id": 1,
    "nombre": "Protein Shake V2",
    "sku": "PROT-SHK-001-B",
    "precio_usd": 48.00,
    "descripcion": "New formula"
}

Get Single Product

Ver Producto Individual

GET /api/productos/ver?id=1 🔓 PublicPúblico

🗺️ Get All Geographic Data

🗺️ Obtener Todos los Datos Geográficos

Retrieve complete hierarchical geographic data (countries, departments, municipalities, neighborhoods).

Obtener datos geográficos jerárquicos completos (países, departamentos, municipios, barrios).

GET /api/geoinfo/listar 🔓 PublicPúblico

Response Structure

Estructura de Respuesta

{
    "success": true,
    "data": {
        "paises": [
            { "id": 1, "nombre": "Nicaragua", "codigo_iso": "NI" }
        ],
        "departamentos": [
            { "id": 1, "nombre": "Managua", "id_pais": 1 }
        ],
        "municipios": [
            { "id": 1, "nombre": "Managua", "id_departamento": 1, "codigo_postal": "10000" }
        ],
        "barrios": [
            { "id": 1, "nombre": "Altamira", "id_municipio": 1, "codigo_postal": "10100" }
        ]
    }
}

🌎 Countries (Países)

🌎 Países

List All Countries

Listar Todos los Países

GET /api/geoinfo/paises 🔓 PublicPúblico
// Response
[
    {
        "id": 1,
        "nombre": "Nicaragua",
        "codigo_iso": "NI",
        "id_moneda_local": 1
    },
    {
        "id": 2,
        "nombre": "Honduras",
        "codigo_iso": "HN",
        "id_moneda_local": 2
    }
]

Get Single Country

Obtener País Individual

GET /api/geoinfo/paises?id=1 🔓 PublicPúblico

🏛️ Departments (Departamentos)

🏛️ Departamentos

List All Departments

Listar Todos los Departamentos

GET /api/geoinfo/departamentos 🔓 PublicPúblico

Filter by Country

Filtrar por País

GET /api/geoinfo/departamentos?id_pais=1 🔓 PublicPúblico
ParameterTypeDescription
id_paisintegerFilter departments by country ID
ParámetroTipoDescripción
id_paisenteroFiltrar departamentos por ID de país
// Response
[
    {
        "id": 1,
        "nombre": "Managua",
        "id_pais": 1
    },
    {
        "id": 2,
        "nombre": "Granada",
        "id_pais": 1
    }
]

🏘️ Municipalities (Municipios)

🏘️ Municipios

List All Municipalities

Listar Todos los Municipios

GET /api/geoinfo/municipios 🔓 PublicPúblico

Filter by Department

Filtrar por Departamento

GET /api/geoinfo/municipios?id_departamento=1 🔓 PublicPúblico
ParameterTypeDescription
id_departamentointegerFilter municipalities by department ID
ParámetroTipoDescripción
id_departamentoenteroFiltrar municipios por ID de departamento
// Response
[
    {
        "id": 1,
        "nombre": "Managua",
        "id_departamento": 1,
        "codigo_postal": "10000"
    },
    {
        "id": 2,
        "nombre": "Tipitapa",
        "id_departamento": 1,
        "codigo_postal": "11000"
    }
]

🏠 Neighborhoods (Barrios)

🏠 Barrios

List All Neighborhoods

Listar Todos los Barrios

GET /api/geoinfo/barrios 🔓 PublicPúblico

Filter by Municipality

Filtrar por Municipio

GET /api/geoinfo/barrios?id_municipio=1 🔓 PublicPúblico
ParameterTypeDescription
id_municipiointegerFilter neighborhoods by municipality ID
ParámetroTipoDescripción
id_municipioenteroFiltrar barrios por ID de municipio
// Response
[
    {
        "id": 1,
        "nombre": "Altamira",
        "id_municipio": 1,
        "codigo_postal": "10100"
    },
    {
        "id": 2,
        "nombre": "Bolonia",
    }\n]\

📮 Postal Codes (Códigos Postales)

📮 Códigos Postales

Resolve postal codes to geographic locations or find postal codes by zone.

Resolver códigos postales a ubicaciones geográficas o buscar códigos postales por zona.

Resolve Postal Code

Resolver Código Postal

GET /api/geoinfo/codigos_postales?action=resolve&cp=<cp>[&id_pais=<id>] 🔓 PublicPúblico
ParameterParámetroTypeTipoReq.Req.DescriptionDescripción
cpstringPostal code to searchCódigo postal a buscar
id_paisintegerFilter by specific country IDFiltrar por ID de país específico
// Response Example (Single Match/Specific)
{
    "ok": true,
    "data": {
        "normalized_cp": "08001",
        "matches": [
            {
                "id_codigo_postal": 542,
                "id_pais": 1,
                "pais": "España",
                "codigo_postal": "08001",
                "id_departamento": 8,
                "departamento": "Barcelona",
                "id_municipio": 12,
                "municipio": "Barcelona",
                "id_barrio": null,
                "barrio": null,
                "partial": false
            }
        ]
    }
}

Find by Zone

Buscar por Zona

Get the postal code for a specific neighborhood.

Obtener el código postal para un barrio específico.

GET /api/geoinfo/codigos_postales?action=find_by_zone&id_pais=<id>&id_barrio=<id> 🔓 PublicPúblico

🔍 Unified Search

🔍 Búsqueda Unificada

Search across all geographic entities (países, departamentos, municipios, barrios) with autocomplete/typeahead functionality.

Buscar en todas las entidades geográficas (países, departamentos, municipios, barrios) con funcionalidad de autocomplete/typeahead.

GET /api/geoinfo/buscar?q=<query> 🔓 PublicPúblico

Query Parameters

Parámetros de Consulta

ParameterTypeRequiredDescription
qstring✅ YesSearch query (min 2 chars)
tipostring❌ NoFilter by type: pais, departamento, municipio, barrio
pais_idinteger❌ NoFilter results within country
departamento_idinteger❌ NoFilter results within department
municipio_idinteger❌ NoFilter results within municipality
ParámetroTipoRequeridoDescripción
qstring✅ SíConsulta de búsqueda (mín 2 caracteres)
tipostring❌ NoFiltrar por tipo: pais, departamento, municipio, barrio
pais_identero❌ NoFiltrar resultados dentro de país
departamento_identero❌ NoFiltrar resultados dentro de departamento
municipio_identero❌ NoFiltrar resultados dentro de municipio

Example Requests

Ejemplos de Peticiones

# 1. Basic search (all types)
GET /api/geoinfo/buscar?q=Guatemala

# 2. Search only countries
GET /api/geoinfo/buscar?q=Guat&tipo=pais

# 3. Search municipalities containing "San"
GET /api/geoinfo/buscar?q=San&tipo=municipio

# 4. Search within specific country (Nicaragua = 1)
GET /api/geoinfo/buscar?q=San&tipo=municipio&pais_id=1

# 5. Search neighborhoods in specific municipality
GET /api/geoinfo/buscar?q=Alta&tipo=barrio&municipio_id=1

# 6. Autocomplete for cascading dropdown
GET /api/geoinfo/buscar?q=Mana&tipo=departamento&pais_id=1

Practical Use Cases

Casos de Uso Prácticos

🎯 Use Case 1: Country Autocomplete 🎯 Caso de Uso 1: Autocomplete de País
// User types "Gua"
fetch('/api/geoinfo/buscar?q=Gua&tipo=pais')
  .then(r => r.json())
  .then(data => {
    // Shows: Guatemala, Guinea, etc.
    populateCountryDropdown(data.data);
  });
🎯 Use Case 2: Cascading Location Selector 🎯 Caso de Uso 2: Selector de Ubicación en Cascada
// Step 1: User selects country
const selectedCountryId = 6; // Guatemala

// Step 2: Search departments in that country
fetch(`/api/geoinfo/buscar?q=${userInput}&tipo=departamento&pais_id=${selectedCountryId}`)
  .then(r => r.json())
  .then(data => populateDepartmentDropdown(data.data));

// Step 3: Search municipalities in selected department
const selectedDepartmentId = 80;
fetch(`/api/geoinfo/buscar?q=${userInput}&tipo=municipio&departamento_id=${selectedDepartmentId}`)
  .then(r => r.json())
  .then(data => populateMunicipalityDropdown(data.data));
🎯 Use Case 3: Quick Global Search 🎯 Caso de Uso 3: Búsqueda Global Rápida
// Search everywhere, get prioritized results
fetch('/api/geoinfo/buscar?q=Managua')
  .then(r => r.json())
  .then(data => {
    // Returns:
    // 1. Departamento "Managua" (priority 3)
    // 2. Municipio "Managua" (priority 5)
    displayResults(data.data);
  });

Example Response

Ejemplo de Respuesta

{
    "success": true,
    "data": [
        {
            "id": 6,
            "tipo": "pais",
            "nombre": "Guatemala",
            "codigo_iso": "GUAT",
            "codigo_postal": null,
            "id_pais": null,
            "pais": null,
            "id_departamento": null,
            "departamento": null,
            "id_municipio": null,
            "municipio": null
        },
        {
            "id": 80,
            "tipo": "departamento",
            "nombre": "Guatemala",
            "codigo_iso": null,
            "codigo_postal": null,
            "id_pais": 6,
            "pais": "Guatemala",
            "id_departamento": null,
            "departamento": null,
            "id_municipio": null,
            "municipio": null
        },
        {
            "id": 1278,
            "tipo": "municipio",
            "nombre": "Antigua Guatemala",
            "codigo_iso": null,
            "codigo_postal": "3001",
            "id_pais": 6,
            "pais": "Guatemala",
            "id_departamento": 89,
            "departamento": "Sacatepequez",
            "id_municipio": null,
            "municipio": null
        },
        {
            "id": 7747,
            "tipo": "barrio",
            "nombre": "Antigua Guatemala",
            "codigo_iso": null,
            "codigo_postal": "3001",
            "id_pais": 6,
            "pais": "Guatemala",
            "id_departamento": 89,
            "departamento": "Sacatepequez",
            "id_municipio": 1278,
            "municipio": "Antigua Guatemala"
        }
    ],
    "query": "Guatemala",
    "filters": []
}
💡 Key Features 💡 Características Clave
  • Priority Ordering: Countries first, then departments, municipalities, and neighborhoods
  • Postal Codes: Neighborhoods inherit postal code from parent municipality if not set
  • Hierarchical Data: Includes parent entity names for complete context
  • Performance: Limited to 20 results, perfect for autocomplete/typeahead
  • Orden por Prioridad: Países primero, luego departamentos, municipios y barrios
  • Códigos Postales: Barrios heredan código postal del municipio si no tienen
  • Datos Jerárquicos: Incluye nombres de entidades padre para contexto completo
  • Rendimiento: Limitado a 20 resultados, perfecto para autocomplete/typeahead

Messenger Application API

API App de Mensajería

Specialized endpoints for the delivery provider app.

Endpoints especializados para la app de los proveedores de mensajería (logística).

Assigned Orders

Mis Asignaciones

Get list of orders assigned to the authenticated provider.

Obtener lista de pedidos asignados al proveedor autenticado.

GET /api/mensajeria/pedidos?page=1&limit=20 👤 Role: MessengerRol: Mensajería
Field / CampoReq.TypeDescription
pageNointeger Page number (default: 1). Número de página (por defecto: 1).
limitNointeger Items per page (default: 20, max: 100). Items por página (por defecto: 20, máx: 100).
estadoNointeger Filter by status ID. Filtrar por ID de estado.
{
    "success": true,
    "data": [
        {
            "ID_Pedido": 100,
            "Numero_Orden": "ORD-2025-001",
            "Estado": "En ruta",
            "Cliente": "Juan Pérez"
        }
    ],
    "pagination": {
        "total": 45,
        "page": 1,
        "limit": 20,
        "total_pages": 3
    }
}

Change Order Status

Cambiar Estado de Pedido

Allows providers and clients to update delivery progress states. Permission rules apply based on role.

Permite a proveedores y clientes actualizar los estados de progreso de entrega. Se aplican reglas de permiso según el rol.

🔒 Role-based restrictions: 🔒 Restricciones por rol:
  • Client (rol=4): Cannot set status to Entregado (3) or Devuelto (7). Also blocked if order is already in those states.
  • Messenger/Provider (rol=5): Full access — can use any state including 3 and 7.
  • Admin: No restrictions.
  • Cliente (rol=4): No puede usar Entregado (3) ni Devuelto (7) como destino. Tampoco puede modificar un pedido que ya esté en esos estados.
  • Mensajería/Proveedor (rol=5): Acceso completo — puede usar cualquier estado incluyendo 3 y 7.
  • Admin: Sin restricciones.
POST /api/mensajeria/cambiar_estado 👤 Role: MessengerRol: Mensajería
Field / CampoReq.Allowed Values / Valores PermitidosDescription
id_pedidoCond.integer (ID) Internal Order ID. Required if numero_orden not provided. ID interno del pedido. Requerido si no se envía numero_orden.
numero_ordenCond.string External Order Number. Required if id_pedido not provided. Número de orden externo. Requerido si no se envía id_pedido.
estadoYesinteger Target Status ID (e.g., 3: Delivered, 4: Rescheduled, 7: Returned). ID del estado destino (ej: 3: Entregado, 4: Reprogramado, 7: Devuelto).
motivoCond.string Reason. Mandatory if status=7. Motivo. Obligatorio si estado=7.
By ID
Por ID
{
    "id_pedido": 150,
    "estado": 4,
    "motivo": "Reprogramar"
}
By Order Num
Por Núm. Orden
{
    "numero_orden": "EXT-88002",
    "estado": 4,
    "motivo": "Reprogramar"
}
Return (Mandatory Motive)
Devolución (Motivo Oblig.)
{
    "numero_orden": "EXT-88002",
    "estado": 7,
    "motivo": "Dirección incorrecta"
}
Error Response (Forbidden transition)
Respuesta de Error (Transición prohibida)
{
    "success": false,
    "message": "No se puede cambiar el estado de un pedido que ya ha sido entregado."
}

Order Status History

Historial de Cambios de Estado

This endpoint allows you to query the full audit trail of status changes for any order. Each record shows the previous state, the new state, the comment left at the time of the change, and who performed it.

Este endpoint permite consultar el historial completo de cambios de estado de los pedidos. Cada registro muestra el estado anterior, el estado nuevo, el comentario del cambio y quién lo realizó.

GET /api/pedidos/historial 🔐 AuthenticatedAutenticado
💡 Tip: 💡 Tip: All filters are optional and can be combined freely. Without filters, all history is returned paginated. Todos los filtros son opcionales y combinables libremente. Sin filtros, se devuelve todo el historial paginado.

Query Parameters

Parámetros de Consulta

Parameter Type Default Description Example
numero_ordenstringFilter by order number100045
id_pedidointegerFilter by internal order ID45
id_estado_anteriorintegerFilter by exact previous state ID1
id_estado_nuevointegerFilter by exact new state ID3
id_estadosstringComma-separated state IDs — matches previous OR new state1,2,3
fecha_desdedateStart date of the change (Y-m-d)2026-03-01
fecha_hastadateEnd date of the change (Y-m-d)2026-03-31
id_usuariointegerFilter by user who made the change7
pageinteger1Page number2
limitinteger20Records per page (max 100)50
Parámetro Tipo Defecto Descripción Ejemplo
numero_ordenstringFiltrar por número de orden100045
id_pedidoenteroFiltrar por ID interno del pedido45
id_estado_anteriorenteroFiltrar por ID exacto del estado anterior1
id_estado_nuevoenteroFiltrar por ID exacto del estado nuevo3
id_estadosstringIDs de estados separados por coma — coincide con anterior O nuevo1,2,3
fecha_desdefechaFecha inicio del cambio (Y-m-d)2026-03-01
fecha_hastafechaFecha fin del cambio (Y-m-d)2026-03-31
id_usuarioenteroFiltrar por usuario que realizó el cambio7
pageentero1Número de página2
limitentero20Registros por página (máx 100)50

Usage Examples

Ejemplos de Uso

1. Full history (paginated)

1. Historial completo (paginado)

GET /api/pedidos/historial
Authorization: Bearer <YOUR_TOKEN>

2. History for a specific order

2. Historial de un pedido específico

GET /api/pedidos/historial?numero_orden=100045
Authorization: Bearer <YOUR_TOKEN>

3. Changes to "Delivered" state in March 2026

3. Cambios a estado "Entregado" en marzo 2026

GET /api/pedidos/historial?id_estado_nuevo=3&fecha_desde=2026-03-01&fecha_hasta=2026-03-31
Authorization: Bearer <YOUR_TOKEN>

4. Orders that passed through states 1, 2 or 7

4. Pedidos que pasaron por los estados 1, 2 o 7

GET /api/pedidos/historial?id_estados=1,2,7&page=1&limit=50
Authorization: Bearer <YOUR_TOKEN>

5. Full cURL example

5. Ejemplo completo con cURL

curl -X GET "http://localhost/paqueteriacz/api/pedidos/historial?numero_orden=100045&page=1&limit=20" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLC..." \
  -H "Content-Type: application/json"

6. JavaScript (fetch)

6. JavaScript (fetch)

const params = new URLSearchParams({
  numero_orden: '100045',
  page: 1,
  limit: 20
});

const res = await fetch(`/api/pedidos/historial?${params}`, {
  headers: { 'Authorization': 'Bearer ' + token }
});
const json = await res.json();
console.log(json.data);       // array de cambios
console.log(json.pagination); // metadatos de paginación

7. PHP (cURL)

7. PHP (cURL)

$ch = curl_init();
curl_setopt_array($ch, [
  CURLOPT_URL            => 'http://localhost/paqueteriacz/api/pedidos/historial?numero_orden=100045',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $token]
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

foreach ($response['data'] as $cambio) {
    echo $cambio['fecha_cambio'] . ': '
       . $cambio['estado_anterior'] . ' → '
       . $cambio['estado_nuevo'] . PHP_EOL;
}

Response Structure

Estructura de Respuesta

Success 200 OK

Éxito 200 OK

{
    "success": true,
    "message": "Se encontraron 42 registros en el historial.",
    "data": [
        {
            "id": 12,
            "id_pedido": 45,
            "numero_orden": "100045",
            "id_estado_anterior": 1,
            "estado_anterior": "En bodega",
            "id_estado_nuevo": 2,
            "estado_nuevo": "En ruta o proceso",
            "comentario": "Recogido por mensajero",
            "id_usuario": 7,
            "realizado_por": "Juan Pérez",
            "fecha_cambio": "2026-03-04 09:30:00"
        },
        {
            "id": 11,
            "id_pedido": 45,
            "numero_orden": "100045",
            "id_estado_anterior": null,
            "estado_anterior": null,
            "id_estado_nuevo": 1,
            "estado_nuevo": "En bodega",
            "comentario": null,
            "id_usuario": 3,
            "realizado_por": "María García",
            "fecha_cambio": "2026-03-03 14:00:00"
        }
    ],
    "pagination": {
        "total": 42,
        "per_page": 20,
        "current_page": 1,
        "total_pages": 3,
        "has_next": true,
        "has_prev": false
    }
}

Response Fields

Campos de la Respuesta

FieldTypeDescription
idintegerUnique ID of the history record
id_pedidointegerInternal order ID
numero_ordenstringOrder number (client reference)
id_estado_anteriorinteger|nullPrevious state ID (null if this was the first transition)
estado_anteriorstring|nullPrevious state name
id_estado_nuevointegerNew state ID after the change
estado_nuevostringNew state name
comentariostring|nullObservation or comment recorded at the time of the change
id_usuariointegerID of the user who made the change
realizado_porstringFull name of the user who made the change
fecha_cambiodatetimeDate and time of the state change
CampoTipoDescripción
identeroID único del registro de historial
id_pedidoenteroID interno del pedido
numero_ordenstringNúmero de orden (referencia del cliente)
id_estado_anteriorentero|nullID del estado anterior (null si es la primera transición)
estado_anteriorstring|nullNombre del estado anterior
id_estado_nuevoenteroID del estado nuevo después del cambio
estado_nuevostringNombre del estado nuevo
comentariostring|nullObservación o comentario registrado al momento del cambio
id_usuarioenteroID del usuario que realizó el cambio
realizado_porstringNombre completo del usuario que realizó el cambio
fecha_cambiodatetimeFecha y hora del cambio de estado

Error Responses

Respuestas de Error

// 401 - No token
{
    "success": false,
    "message": "Token de autorización requerido.",
    "data": null
}

// 400 - Bad date format
{
    "success": false,
    "message": "Formato de fecha_desde inválido. Use Y-m-d (ej: 2026-03-01).",
    "data": null
}

State ID Reference

Referencia de IDs de Estado

Use these IDs in id_estado_anterior, id_estado_nuevo or id_estados filter parameters.

Usa estos IDs en los parámetros de filtro id_estado_anterior, id_estado_nuevo o id_estados.

ID State NameNombre del Estado CategoryCategoría DescriptionDescripción
1 En bodega InitialInicial Order received and stored at warehousePedido recibido y almacenado en bodega
2 En ruta o proceso In TransitEn tránsito Order is out for deliveryPedido en camino al destinatario
3 Entregado CompletedCompletado Order successfully delivered to recipientPedido entregado exitosamente al destinatario
4 Reprogramado RescheduledReprogramado Delivery rescheduled for another day/timeEntrega reprogramada para otra fecha/hora
5 Domicilio cerrado IssueIncidencia Delivery failed: location was closedFalló la entrega: el domicilio estaba cerrado
6 No hay quien reciba IssueIncidencia Delivery failed: no one available to receiveFalló la entrega: nadie disponible para recibir
7 Devuelto ReturnedDevuelto Order returned to warehousePedido devuelto a bodega
8 Domicilio no encontrado IssueIncidencia Address could not be locatedLa dirección no pudo ser ubicada
9 Rechazado RejectedRechazado Customer refused to receive the orderEl cliente rechazó recibir el pedido
10 No puede pagar recaudo IssueIncidencia Customer unable to pay cash on deliveryCliente no pudo pagar el recaudo al recibir
11 Pendiente recolección In TransitEn tránsito Waiting for messenger pick upEsperando recolección por mensajería
12 Recolectado por mensajería In TransitEn tránsito Picked up by the messenger serviceRecolectado por el servicio de mensajería
13 Traslado a punto In TransitEn tránsito Being moved to distribution pointEn traslado hacia punto de distribución
14 Entregado-liquidado SettledLiquidado Order delivered and payment settledPedido entregado y pago liquidado
15 Devuelto a bodega ReturnedDevuelto Final return: delivered back to main warehouseDevolución final: entregado de vuelta en bodega
16 Incidencia IssueIncidencia General delivery issueIncidencia general en la entrega
17 Cancelado CancelledCancelado Order cancelledPedido cancelado
18 Correo In TransitEn tránsito Order dispatched via postal mail, delivery pending confirmationPedido despachado por correo postal, entrega pendiente de confirmación
19 Disponible para retirar en Agencia Pending PickupPendiente retiro Package could not be delivered to address; available for pickup at agency branchEl paquete no pudo entregarse en domicilio; disponible para retiro en agencia
⚠️ Note: ⚠️ Nota: The list of states above may grow over time. Use GET /api/pedidos/estados to always retrieve the current, up-to-date list from the database. La lista de estados puede crecer con el tiempo. Usa GET /api/pedidos/estados para obtener siempre la lista actualizada desde la base de datos.
🔧 How history records are created: 🔧 Cómo se generan los registros del historial:
  • Each state change is recorded automatically by a database trigger (AFTER UPDATE on pedidos).
  • When an operator adds a comment/observation during a state change (e.g. from the Logistics dashboard), the PHP layer updates the observaciones column of the latest history record for that order.
  • This two-step approach prevents duplicate entries — the trigger owns the INSERT, PHP only annotates it.
  • Cada cambio de estado es registrado automáticamente por un trigger de base de datos (AFTER UPDATE sobre la tabla pedidos).
  • Cuando un operador incluye un comentario/observación durante el cambio de estado (por ejemplo desde el panel de Logística), la capa PHP actualiza la columna observaciones del último registro de historial de ese pedido.
  • Este enfoque en dos pasos evita entradas duplicadas: el trigger es dueño del INSERT, PHP solo lo anota.

⚙️ Logistics Job Status

⚙️ Estado de Jobs Logísticos

Returns processing jobs related to logistics automation (validation, guide generation, tracking updates) for one or many orders.

Devuelve los trabajos de procesamiento relacionados con automatización logística (validación, guía, tracking) para uno o varios pedidos.

GET /api/pedidos/status 🔐 AuthenticatedAutenticado

Modes

Modos

  • ?numero_orden=87416381 Single order
  • ?numeros_orden=87416381,87416382 Batch (max 50)
  • No params: provider dashboard summary
  • ?numero_orden=87416381 Pedido único
  • ?numeros_orden=87416381,87416382 Lote (máx 50)
  • Sin parámetros: resumen de dashboard del proveedor

Single Response 200 OK

Respuesta Single 200 OK

{
  "success": true,
  "message": "Estado trabajos pedido",
  "data": {
    "numero_orden": "87416381",
    "has_jobs": true,
    "jobs": [
      {
        "job_type": "validar_direccion",
        "status": "completed",
        "attempts": 1,
        "updated_at": "2026-04-08 14:20:00",
        "error": null
      }
    ],
    "observacion_estado": "Estado cambiado automáticamente",
    "fecha_observacion_estado": "2026-04-07 16:15:00",
    "observacion_por": "Proveedor RutaEX Pulox CR"
  }
}

Batch Response 200 OK

Respuesta Batch 200 OK

{
  "success": true,
  "message": "Resultados batch",
  "data": {
    "results": [
      {
        "numero_orden": "87416381",
        "found": true,
        "jobs": [],
        "observacion_estado": null,
        "fecha_observacion_estado": null,
        "observacion_por": null
      }
    ]
  }
}

📦 Current Order Status

📦 Estado Actual de Pedidos

Returns the current state of each order directly from the pedidos table. Unlike /historial (which shows state changes), this endpoint shows every order with its present status — including orders that have never had a recorded state change.

Devuelve el estado actual de cada pedido directamente desde la tabla pedidos. A diferencia de /historial (que muestra cambios de estado), este endpoint muestra todos los pedidos con su estado vigente — incluyendo pedidos que nunca tuvieron un cambio de estado registrado.

GET /api/pedidos/estado_pedidos 🔐 AuthenticatedAutenticado
💡 When to use this vs /historial: 💡 ¿Cuándo usar este vs /historial?
  • Use /estado_pedidos to know where an order is right now.
  • Use /historial to see how it got there (the full audit trail of transitions).
  • Usa /estado_pedidos para saber dónde está un pedido ahora mismo.
  • Usa /historial para ver cómo llegó ahí (trazabilidad completa de transiciones).

Query Parameters

Parámetros de Consulta

ParameterTypeDefaultDescriptionExample
numero_ordenstringExact order number81154737
id_estadointegerFilter by current state ID1
id_clienteintegerFilter by client ID5
id_proveedorintegerFilter by provider/messenger ID3
fecha_desdedateOrder entry date start (Y-m-d)2026-03-01
fecha_hastadateOrder entry date end (Y-m-d)2026-03-31
pageinteger1Page number2
limitinteger20Records per page (max 100)50
ParámetroTipoDefectoDescripciónEjemplo
numero_ordenstringNúmero de orden exacto81154737
id_estadoenteroFiltrar por ID de estado actual1
id_clienteenteroFiltrar por ID de cliente5
id_proveedorenteroFiltrar por ID de proveedor/mensajero3
fecha_desdefechaFecha ingreso desde (Y-m-d)2026-03-01
fecha_hastafechaFecha ingreso hasta (Y-m-d)2026-03-31
pageentero1Número de página2
limitentero20Registros por página (máx 100)50

Usage Examples

Ejemplos de Uso

1. All orders (paginated)
1. Todos los pedidos (paginado)
GET /api/pedidos/estado_pedidos
Authorization: Bearer <YOUR_TOKEN>
2. Specific order
2. Pedido específico
GET /api/pedidos/estado_pedidos?numero_orden=81154737
Authorization: Bearer <YOUR_TOKEN>
3. All orders currently "En bodega"
3. Todos los pedidos actualmente en bodega
GET /api/pedidos/estado_pedidos?id_estado=1&page=1&limit=50
Authorization: Bearer <YOUR_TOKEN>
4. Orders by date range
4. Pedidos por rango de fecha
GET /api/pedidos/estado_pedidos?fecha_desde=2026-03-01&fecha_hasta=2026-03-20
Authorization: Bearer <YOUR_TOKEN>

Response 200 OK

Respuesta 200 OK

{
    "success": true,
    "message": "Se encontraron 3 pedidos.",
    "data": [
        {
            "id": 45,
            "numero_orden": "81154737",
            "destinatario": "Juan Pérez",
            "id_estado": 1,
            "estado_actual": "En bodega",
            "observacion_estado": "Estado cambiado automáticamente",
            "fecha_observacion_estado": "2026-03-10 09:10:00",
            "observacion_por": "Proveedor RutaEX Pulox CR",
            "fecha_ingreso": "2026-03-10 09:00:00",
            "fecha_actualizacion": "2026-03-10 09:00:00"
        },
        {
            "id": 46,
            "numero_orden": "81154738",
            "destinatario": "María López",
            "id_estado": 3,
            "estado_actual": "Entregado",
            "observacion_estado": null,
            "fecha_observacion_estado": null,
            "observacion_por": null,
            "fecha_ingreso": "2026-03-11 10:30:00",
            "fecha_actualizacion": "2026-03-12 14:20:00"
        }
    ],
    "pagination": {
        "total": 3,
        "per_page": 20,
        "current_page": 1,
        "total_pages": 1,
        "has_next": false,
        "has_prev": false
    }
}

Response Fields

Campos de la Respuesta

FieldTypeDescription
idintegerInternal order ID
numero_ordenstringOrder number (client reference)
destinatariostringRecipient name
id_estadointegerCurrent state ID
estado_actualstringCurrent state name
observacion_estadostring/nullLatest observation/comment for the order status
fecha_observacion_estadodatetime/nullTimestamp of the latest observation
observacion_porstring/nullUser/provider who registered the latest observation
fecha_ingresodatetimeDate the order was registered
fecha_actualizaciondatetimeDate of last update
CampoTipoDescripción
identeroID interno del pedido
numero_ordenstringNúmero de orden (referencia del cliente)
destinatariostringNombre del destinatario
id_estadoenteroID del estado actual
estado_actualstringNombre del estado actual
observacion_estadostring/nullÚltima observación/comentario del estado
fecha_observacion_estadodatetime/nullFecha/hora de la última observación
observacion_porstring/nullUsuario/proveedor que registró la observación
fecha_ingresodatetimeFecha en que se registró el pedido
fecha_actualizaciondatetimeFecha de la última actualización

🔗 Forwarding Provider Status Webhook

🔗 Webhook de Estados (Forwarding)

Endpoint designed to receive real-time order status updates from Forwarding Providers.

Endpoint diseñado para recibir actualizaciones de estado de pedidos en tiempo real desde Proveedores de Forwarding.

POST /api/forwarding/webhook_estados.php 🔒 Bearer Token RequiredRequiere Bearer Token

Headers

Headers

Authorization: Bearer <webhook_secret>
Content-Type: application/json
💡 Authentication: 💡 Autenticación: The webhook_secret must match the token configured in the corresponding Provider settings within the Forwarding module. El webhook_secret debe coincidir con el token configurado en los ajustes del Proveedor correspondiente dentro del módulo de Forwarding.

Expected JSON Payload

JSON Esperado

{
  "customersId": 54,
  "auditUser": "rutaexmex.api",
  "state": "Reprogramado",
  "substate": "Nuevo Intento",
  "dateToReceive": "2026-05-04",
  "notes": "Entrega programada para mañana.",
  "ordersNumbers": [
    { "orderNumber": "123987123456" },
    { "orderNumber": "414141" }
  ]
}

Field Mapping

Mapeo de Campos

Provider FieldDescription
state & substateMapped to internal states (e.g. Reprogramado, Cancelado).
dateToReceiveUpdates order delivery date (Required if state is Reprogramado). Format: YYYY-MM-DD.
notes & auditUserAppended to the order's status history log.
ordersNumbersList of order numbers to apply the status update to.
Campo del ProveedorDescripción
state y substateMapeado a estados internos (Ej. Reprogramado, Cancelado).
dateToReceiveActualiza la fecha de entrega (Obligatorio si el estado es Reprogramado). Formato: YYYY-MM-DD.
notes y auditUserSe añade al historial de estados del pedido.
ordersNumbersLista de números de orden a los que aplicar la actualización.

Response 200 OK

Respuesta 200 OK

{
  "success": true,
  "processed": 1,
  "failed": 1,
  "results": [
    { "orderNumber": "123987123456", "updated": true },
    { "orderNumber": "414141", "updated": false, "error": "Orden no encontrada en el sistema." }
  ]
}

📅 Reschedule an Order

📅 Reprogramar un Pedido

Changes the order status to the indicated state (ID 4 = Rescheduled by default), updates the delivery date, optionally reassigns the client, and records the reason in the status history. The operation is atomic — all changes happen inside a single transaction.

Cambia el estado del pedido al estado indicado (ID 4 = Reprogramado por defecto), actualiza la fecha de entrega, opcionalmente reasigna el cliente y registra el motivo en el historial de estados. La operación es atómica — todos los cambios ocurren dentro de una sola transacción.

POST /api/pedidos/reprogramar 🔐 AuthenticatedAutenticado

Request Body (application/json)

Cuerpo de la Petición (application/json)

FieldTypeRequiredDescriptionExample
numero_ordenstring✅ YesOrder number to reschedule"81154737"
fecha_entregastring⚠️ Cond.New delivery date (ISO 8601 — YYYY-MM-DD). Required only when id_estado = 4 (Rescheduled). Optional for other states."2026-05-20"
id_estadointeger⬜ NoTarget state ID. Must exist in estados_pedidos. Defaults to 4 (Rescheduled).4
id_clienteinteger⬜ NoClient ID to assign to the order. If provided, updates id_cliente in the same atomic transaction.42
motivostring⬜ NoReason for rescheduling"Cliente ausente"
CampoTipoReq.DescripciónEjemplo
numero_ordenstring✅ SíNúmero de orden a reprogramar"81154737"
fecha_entregastring⚠️ Cond.Nueva fecha de entrega (ISO 8601 — YYYY-MM-DD). Solo requerida cuando id_estado = 4 (Reprogramado). Opcional para otros estados."2026-05-20"
id_estadoentero⬜ NoID del estado destino. Debe existir en estados_pedidos. Por defecto 4 (Reprogramado).4
id_clienteentero⬜ NoID del cliente a asignar al pedido. Si se provee, actualiza id_cliente en la misma transacción atómica.42
motivostring⬜ NoRazón de la reprogramación"Cliente ausente"

Example Request (curl)

Ejemplo de Petición (curl)

curl -X POST "http://localhost/paqueteriacz/api/pedidos/reprogramar" \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "numero_orden": "81154737",
    "fecha_entrega": "2026-05-20",
    "id_estado": 4,
    "id_cliente": 42,
    "motivo": "Cliente ausente en primer intento"
  }'

Example Request (JavaScript)

Ejemplo de Petición (JavaScript)

const res = await fetch('/api/pedidos/reprogramar', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <YOUR_TOKEN>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    numero_orden: '81154737',
    fecha_entrega: '2026-05-20',
    id_estado: 4,
    id_cliente: 42,
    motivo: 'Cliente ausente en primer intento'
  })
});
const json = await res.json();
console.log(json.data); // { numero_orden, id_estado, id_cliente, fecha_entrega, motivo, reprogramado_en }

Response 200 OK

Respuesta 200 OK

{
  "success": true,
  "message": "Pedido 81154737 reprogramado para el 2026-05-20.",
  "data": {
    "numero_orden":    "81154737",
    "id_estado":       4,
    "id_cliente":      42,
    "fecha_entrega":   "2026-05-20",
    "motivo":          "Cliente ausente en primer intento",
    "reprogramado_en": "2026-05-05 14:30:00"
  }
}

Error Responses

Respuestas de Error

HTTPCauseCausa
400Missing required fields, invalid date format, past date, or non-existent id_estado.Campos requeridos faltantes, formato de fecha inválido, fecha en el pasado o id_estado inexistente.
401Missing or invalid JWT token.Token JWT ausente o inválido.
403No permission over the order, or role not allowed to use the target state.Sin permiso sobre el pedido, o el rol no puede usar el estado destino.
404Order not found.Pedido no encontrado.
💡 Key Behaviors 💡 Comportamientos Clave
  • Atomic transaction: State change + date update + optional client reassignment + history entry happen in one DB transaction.
  • State validation: id_estado must be in range 1–13 or 15–17. Returns 400 if outside this range or non-existent.
  • fecha_entrega: Only required when id_estado = 4 (Reprogramado). Optional for all other states.
  • Client reassignment: If id_cliente is provided, the order's client is updated in the same transaction.
  • Role restrictions: Clients (rol=4) cannot use Entregado (3) or Devuelto (7). Blocked if order is already in a terminal state. Messengers (rol=5) and admins have full access.
  • Default state: If id_estado is omitted, defaults to 4 (Reprogramado).
  • Transacción atómica: Cambio de estado + actualización de fecha + reasignación opcional de cliente + entrada en historial ocurren en una sola transacción DB.
  • Validación de estado: id_estado debe estar en el rango 1–13 o 15–17. Retorna 400 si está fuera del rango o no existe.
  • fecha_entrega: Solo requerida cuando id_estado = 4 (Reprogramado). Opcional para cualquier otro estado.
  • Reasignación de cliente: Si se provee id_cliente, el cliente del pedido se actualiza en la misma transacción.
  • Restricciones por rol: Clientes (rol=4) no pueden usar Entregado (3) ni Devuelto (7). Bloqueados si el pedido ya está en estado terminal. Mensajería (rol=5) y admins tienen acceso completo.
  • Estado por defecto: Si se omite id_estado, usa 4 (Reprogramado).

📅 Rescheduled Orders

📅 Consulta de Órdenes Reprogramadas

Standard endpoint to query all orders currently in Rescheduled status (state ID 4). Returns the new delivery date, the reason for rescheduling, who performed it, and when. The response is automatically scoped to the authenticated client — admins see all orders.

Endpoint estándar para consultar todas las órdenes actualmente en estado Reprogramado (ID 4). Devuelve la nueva fecha de entrega, el motivo del cambio, quién lo realizó y cuándo. La respuesta se limita automáticamente al cliente autenticado — los administradores ven todos los pedidos.

GET /api/pedidos/reprogramaciones 🔐 AuthenticatedAutenticado
✅ Key difference vs /estado_pedidos?id_estado=4: ✅ Diferencia clave vs /estado_pedidos?id_estado=4:
  • Returns fecha_entrega (the new scheduled delivery date).
  • Returns motivo (reason recorded at the time of rescheduling).
  • Returns reprogramado_por (who changed the state — user or external API).
  • Returns fecha_reprogramacion (exact timestamp the reschedule was logged).
  • Date filters apply to when the reschedule occurred, not order entry date.
  • Devuelve fecha_entrega (la nueva fecha de entrega programada).
  • Devuelve motivo (razón registrada al momento de reprogramar).
  • Devuelve reprogramado_por (quién cambió el estado — usuario o API externa).
  • Devuelve fecha_reprogramacion (timestamp exacto en que se registró la reprogramación).
  • Los filtros de fecha aplican sobre cuándo ocurrió la reprogramación, no la fecha de ingreso del pedido.

Query Parameters

Parámetros de Consulta

All parameters are optional and combinable. Without filters, all rescheduled orders visible to the authenticated user are returned. Todos los parámetros son opcionales y combinables. Sin filtros, se devuelven todas las órdenes reprogramadas visibles para el usuario autenticado.
ParameterTypeDefaultDescriptionExample
numero_ordenstringFilter by exact order number81154737
fecha_desdedateRescheduling date start (Y-m-d)2026-05-01
fecha_hastadateRescheduling date end (Y-m-d)2026-05-31
pageinteger1Page number2
limitinteger20Records per page (max 100)50
ParámetroTipoDefectoDescripciónEjemplo
numero_ordenstringFiltrar por número de orden exacto81154737
fecha_desdefechaFecha de reprogramación desde (Y-m-d)2026-05-01
fecha_hastafechaFecha de reprogramación hasta (Y-m-d)2026-05-31
pageentero1Número de página2
limitentero20Registros por página (máx 100)50

Usage Examples

Ejemplos de Uso

1. All rescheduled orders (paginated)

1. Todas las órdenes reprogramadas (paginado)

GET /api/pedidos/reprogramaciones
Authorization: Bearer <YOUR_TOKEN>

2. Specific rescheduled order

2. Reprogramación de un pedido específico

GET /api/pedidos/reprogramaciones?numero_orden=81154737
Authorization: Bearer <YOUR_TOKEN>

3. Rescheduled during May 2026

3. Reprogramadas durante mayo 2026

GET /api/pedidos/reprogramaciones?fecha_desde=2026-05-01&fecha_hasta=2026-05-31
Authorization: Bearer <YOUR_TOKEN>

4. Full cURL example

4. Ejemplo completo con cURL

curl -X GET "http://localhost/paqueteriacz/api/pedidos/reprogramaciones?fecha_desde=2026-05-01&page=1&limit=50" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLC..." \
  -H "Content-Type: application/json"

5. JavaScript (fetch)

5. JavaScript (fetch)

const params = new URLSearchParams({
  fecha_desde: '2026-05-01',
  fecha_hasta: '2026-05-31',
  page: 1,
  limit: 50
});

const res = await fetch(`/api/pedidos/reprogramaciones?${params}`, {
  headers: { 'Authorization': 'Bearer ' + token }
});
const json = await res.json();
console.log(json.data);       // array de reprogramaciones
console.log(json.pagination); // metadatos de paginación

6. PHP (cURL)

6. PHP (cURL)

$ch = curl_init();
curl_setopt_array($ch, [
  CURLOPT_URL            => 'http://localhost/paqueteriacz/api/pedidos/reprogramaciones?fecha_desde=2026-05-01',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $token]
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

foreach ($response['data'] as $orden) {
    echo $orden['numero_orden'] . ' → nueva entrega: ' . $orden['fecha_entrega']
       . ' (reprogramado por: ' . $orden['reprogramado_por'] . ')' . PHP_EOL;
}

Response Structure

Estructura de Respuesta

Success 200 OK

Éxito 200 OK

{
    "success": true,
    "message": "Se encontraron 3 órdenes reprogramadas.",
    "data": [
        {
            "numero_orden":          "81154737",
            "destinatario":          "Juan Pérez",
            "direccion":             "Av. Central 123, Col. Centro",
            "estado_actual":         "Reprogramado",
            "fecha_entrega":         "2026-05-20",
            "motivo":                "Cliente ausente en primer intento",
            "reprogramado_por":      "rutaexmex.api",
            "fecha_reprogramacion":  "2026-05-05 14:30:00"
        },
        {
            "numero_orden":          "81154738",
            "destinatario":          "María López",
            "direccion":             "Calle 5 Norte #22",
            "estado_actual":         "Reprogramado",
            "fecha_entrega":         "2026-05-22",
            "motivo":                "Domicilio cerrado",
            "reprogramado_por":      "Carlos Mendoza",
            "fecha_reprogramacion":  "2026-05-05 09:15:00"
        }
    ],
    "pagination": {
        "total":        3,
        "per_page":     20,
        "current_page": 1,
        "total_pages":  1,
        "has_next":     false,
        "has_prev":     false
    }
}

Response Fields

Campos de la Respuesta

FieldTypeDescription
numero_ordenstringOrder number (client reference)
destinatariostringRecipient full name
direccionstringDelivery address
estado_actualstringAlways "Reprogramado"
fecha_entregadate / nullNew scheduled delivery date (YYYY-MM-DD). Null if the field was not updated.
motivostring / nullReason recorded when the order was rescheduled
reprogramado_porstring / nullName of the user or external API that changed the status
fecha_reprogramaciondatetime / nullTimestamp of the last rescheduling event (America/Managua)
CampoTipoDescripción
numero_ordenstringNúmero de orden (referencia del cliente)
destinatariostringNombre completo del destinatario
direccionstringDirección de entrega
estado_actualstringSiempre "Reprogramado"
fecha_entregafecha / nullNueva fecha de entrega programada (YYYY-MM-DD). Null si el campo no fue actualizado.
motivostring / nullRazón registrada cuando se reprogramó el pedido
reprogramado_porstring / nullNombre del usuario o API externa que cambió el estado
fecha_reprogramaciondatetime / nullTimestamp del último evento de reprogramación (America/Managua)

Error Responses

Respuestas de Error

// 401 - Sin token
{
    "success": false,
    "message": "Token de autorización requerido.",
    "data": null
}

// 400 - Formato de fecha incorrecto
{
    "success": false,
    "message": "Formato de fecha_desde inválido. Use YYYY-MM-DD.",
    "data": null
}

// 200 - Sin resultados
{
    "success": true,
    "message": "No se encontraron órdenes reprogramadas con los filtros indicados.",
    "data": []
}