Entrega y Envíos
Estos endpoints cubren todo lo que ocurre después de que un pedido fue procesado: registrar la entrega, confirmarla, subir evidencia (fotos/documentos), adjuntar información de un envío externo y gestionar su costo. Para la parte de preparación y envío en sí, consulta Preparación y Envío.
Envelope de respuesta
Toda respuesta exitosa de recurso único sigue { "data": {...} }. Los errores siempre son { "error": { "code", "message", "details?" } } con códigos namespace:snake_case.
Marcar como entregado
Marca el pedido como entregado. La fecha de entrega es opcional — si la omites, se usa la hora del servidor.
orderIdstringrequiredID del pedido
deliveredAtstringFecha/hora ISO 8601 de la entrega. Si se omite, se usa el momento en que llega la petición.
{
"deliveredAt": "2026-07-20T18:30:00.000Z"
}{
"data": {
"_id": "65f3a1b2c4d5e6f7a8b9c0d1",
"orderStatus": "delivered",
"_links": {
"returns": "/orders/65f3a1b2c4d5e6f7a8b9c0d1/returns"
}
}
}
Permiso requerido: orders:update
curl -X POST https://api.fenicia.io/orders/65f3a1b2c4d5e6f7a8b9c0d1/mark-delivered \
-H "Authorization: Bearer fkapi_tu_api_key" \
-H "Content-Type: application/json" \
-d '{"deliveredAt":"2026-07-20T18:30:00.000Z"}'Confirmar entrega
Confirma formalmente la entrega de un pedido, con notas opcionales.
orderIdstringrequiredID del pedido
notesstringNotas asociadas a la confirmación de entrega.
{
"notes": "Recibido por el cliente en recepción"
}{
"data": {
"_id": "65f3a1b2c4d5e6f7a8b9c0d1",
"orderStatus": "delivered",
"_links": {}
}
}
Permiso requerido: orders:fulfill
curl -X PUT https://api.fenicia.io/orders/65f3a1b2c4d5e6f7a8b9c0d1/confirm-delivery \
-H "Authorization: Bearer fkapi_tu_api_key" \
-H "Content-Type: application/json" \
-d '{"notes":"Recibido por el cliente en recepción"}'Subir evidencia de entrega
Registra evidencia de entrega (fotos, documentos) asociada al pedido.
orderIdstringrequiredID del pedido
evidenceUrlstringrequiredURL de la evidencia (foto o documento). Debe ser una URL válida.
evidenceTypestringTipo de evidencia (texto libre, ej. 'photo', 'signature').
notesstringNotas asociadas a la evidencia.
{
"evidenceUrl": "https://fenicia-order-attachments-prod.s3.us-east-2.amazonaws.com/evidence/delivery-photo.jpg",
"evidenceType": "photo",
"notes": "Entregado en la puerta principal"
}{
"data": {
"_id": "65f3a1b2c4d5e6f7a8b9c0d1",
"orderStatus": "delivered",
"_links": {}
}
}
Permiso requerido: orders:update
No sube el archivo — solo registra su URL
Este endpoint NO es un flujo de subida en dos pasos como el de adjuntos de pedido (URL prefirmada de S3 + confirmación). evidenceUrl es la URL ya existente de la evidencia (por ejemplo, una foto que subiste tú mismo a tu propio storage o vía el flujo de adjuntos) — este endpoint solo la asocia al pedido, no aloja el archivo.
Adjuntar guía de envío externa
Adjunta al pedido los datos de una guía de envío generada fuera de Fenicia (por ejemplo, comprada directamente con la paquetería).
orderIdstringrequiredID del pedido
trackingNumberstringrequiredNúmero de rastreo de la guía.
carrierstringrequiredCódigo de la paquetería.
trackingUrlstringURL pública de rastreo.
{
"trackingNumber": "1Z999AA10123456784",
"carrier": "fedex"
}{
"data": {
"_id": "65f3a1b2c4d5e6f7a8b9c0d1",
"orderStatus": "fulfilled",
"_links": {}
}
}
Permiso requerido: orders:update
curl -X POST https://api.fenicia.io/orders/65f3a1b2c4d5e6f7a8b9c0d1/upload-guide \
-H "Authorization: Bearer fkapi_tu_api_key" \
-H "Content-Type: application/json" \
-d '{"trackingNumber":"1Z999AA10123456784","carrier":"fedex"}'Adjuntar información de envío
Adjunta al pedido la información completa de un envío: paquetería, costo, guía, fechas estimadas, origen/destino y dimensiones del paquete.
orderIdstringrequiredID del pedido
trackingNumberstringrequiredNúmero de rastreo.
carrierstringrequiredCódigo de paquetería.
shipmentIdstringID del shipment, si ya existe uno a actualizar.
waybillIdstringID de la guía/waybill.
carrierNamestringNombre visible de la paquetería.
serviceNamestringNombre del servicio de envío (ej. 'Express', 'Terrestre').
providerstringProveedor que originó el envío (ej. agregador de paqueterías).
providerShipmentIdstringID del envío en el sistema del proveedor.
costobjectCosto del envío: { providerCost, feniciaFee, totalCost, currency }.
trackingUrlstringURL pública de rastreo.
labelUrlstringURL de la guía en PDF.
labelS3KeystringKey de S3 donde vive la guía, si Fenicia la almacenó.
deliveryDaysnumberDías estimados de tránsito.
estimatedDeliveryDatestringFecha estimada de entrega (ISO 8601).
purchasedAtstringFecha en que se compró el envío (ISO 8601).
printingFormatstring'standard' o 'thermal'.
originobjectDirección de origen del envío.
destinationobjectDirección de destino del envío.
packageobjectDimensiones del paquete: { weight, weightUnit, length, width, height, dimensionUnit }.
{
"trackingNumber": "1Z999AA10123456784",
"carrier": "fedex",
"cost": { "providerCost": 180.00, "feniciaFee": 15.00, "totalCost": 195.00, "currency": "MXN" }
}{
"data": {
"_id": "65f3a1b2c4d5e6f7a8b9c0d1",
"orderStatus": "fulfilled",
"fulfillmentMode": "fenicia-shippments",
"_links": {}
}
}
Permiso requerido: orders:update
Forma de cost (opcional)
| Campo | Tipo | Descripción |
|---|---|---|
providerCost | number | Costo cobrado por el proveedor de envío. |
feniciaFee | number | Comisión de Fenicia sobre el envío. |
totalCost | number | Costo total (providerCost + feniciaFee, salvo ajustes). |
currency | string | Moneda de 3 letras (ej. MXN). |
Forma de package (opcional)
| Campo | Tipo | Descripción |
|---|---|---|
weight | number | Peso del paquete. |
weightUnit | string | Unidad de peso (ej. kg). |
length / width / height | number | Dimensiones. |
dimensionUnit | string | Unidad de dimensiones (ej. cm). |
carrier === 'other'
Si carrier es "other", revisa si tu integración requiere un nombre descriptivo — usa carrierName para eso.
curl -X POST https://api.fenicia.io/orders/65f3a1b2c4d5e6f7a8b9c0d1/attach-shipment \
-H "Authorization: Bearer fkapi_tu_api_key" \
-H "Content-Type: application/json" \
-d '{
"trackingNumber": "1Z999AA10123456784",
"carrier": "fedex",
"cost": { "providerCost": 180.00, "feniciaFee": 15.00, "totalCost": 195.00, "currency": "MXN" }
}'Costo de un shipment
Actualiza o define el costo de un shipment específico dentro del pedido.
orderIdstringrequiredID del pedido
shipmentIdstringrequiredID del shipment dentro del pedido
amountnumberrequiredMonto pagado por el envío (≥ 0).
currencystringrequiredMoneda ISO 4217 de 3 letras (ej. MXN).
{
"amount": 195.00,
"currency": "MXN"
}{
"data": {
"orderId": "65f3a1b2c4d5e6f7a8b9c0d1",
"shipmentId": "65f3a1b2c4d5e6f7a8b9c0e2",
"shippingCost": { "amount": 195.00, "currency": "MXN" }
}
}
Permiso requerido: orders:update
Este endpoint es solo el costo — no reemplaza attach-shipment
PUT .../shipping-cost únicamente captura o actualiza el monto pagado por un shipment que ya existe en el pedido (identificado por shipmentId); no crea el shipment ni acepta los demás campos de attach-shipment (guía, paquetería, fechas). Cada operación emite un evento de dominio que lambda-finance-events refleja como un Expense en @fenicia/finance-service.
Elimina el costo previamente asignado a un shipment del pedido.
orderIdstringrequiredID del pedido
shipmentIdstringrequiredID del shipment dentro del pedido
{
"data": {
"orderId": "65f3a1b2c4d5e6f7a8b9c0d1",
"shipmentId": "65f3a1b2c4d5e6f7a8b9c0e2",
"removed": true
}
}
Permiso requerido: orders:update
Idempotente: removed indica si había costo previo
Si el shipment ya no tenía costo asignado, la llamada igual responde 200 con removed: false — no es un error, es idempotencia intencional (los consumidores de eventos pueden entregar la misma remoción dos veces). Un shipmentId que no existe en el pedido sí devuelve orders:shipment_not_found (404).
curl -X DELETE https://api.fenicia.io/orders/65f3a1b2c4d5e6f7a8b9c0d1/shipments/65f3a1b2c4d5e6f7a8b9c0e2/shipping-cost \
-H "Authorization: Bearer fkapi_tu_api_key"Descargar guías de envío de un pedido
Devuelve URLs presignadas de S3 para descargar las guías de envío del pedido. Cada PDF se persiste como adjunto del pedido (la primera vez) o se sirve desde caché S3 en llamadas posteriores.
orderIdstringrequiredID del pedido
{
"data": {
"orderId": "65f3a1b2c4d5e6f7a8b9c0d1",
"totalLabels": 1,
"labels": [
{
"identifier": "T1-2026-04-27-00042",
"downloadUrl": "https://fenicia-order-attachments-prod.s3.us-east-2.amazonaws.com/attachments/...?X-Amz-Signature=...",
"filename": "t1-T1-2026-04-27-00042_shipping_label.pdf",
"contentType": "application/pdf",
"size": 51234,
"expiresIn": 900,
"source": "live",
"carrier": "T1-via-Estafeta",
"attachmentId": "65f3a1b2c4d5e6f7a8b9c0e5"
}
],
"processingTimeMs": 432
}
}
Permiso requerido: orders:read
El PDF nunca viaja en base64
Se persiste como adjunto del pedido en S3 y la API responde con una URL presignada (TTL ~15 min). Descarga el PDF directamente desde esa URL — no necesitas tu API key para ese segundo paso. Llamadas repetidas para el mismo pedido reutilizan el adjunto en caché.
LABEL_URL=$(curl -s https://api.fenicia.io/orders/65f3a1b2c4d5e6f7a8b9c0d1/download-shipping-label \
-H "Authorization: Bearer fkapi_tu_api_key" \
| jq -r '.data.labels[0].downloadUrl')
curl -o guia.pdf "$LABEL_URL"Tip
Para impresión en lote de alto volumen, usa POST /orders/fulfillment/labels (ver Preparación y Envío) con varios IDs de pedido a la vez.
Errores
| Código | Status | Descripción |
|---|---|---|
orders:not_found | 404 | No existe un pedido con ese ID en tu tenant. |
orders:cannot_confirm_delivery | 422 | El pedido no está en un estado desde el que se pueda confirmar entrega. |
orders:shipment_not_found | 404 | No existe un shipment con ese ID dentro del pedido. |
orders:shipping_info_required | 400 | Falta información de envío requerida para la operación. |
orders:shipping_label_not_available | 422 | No hay guía disponible para generar/descargar en el estado actual. |
validation:invalid_input / validation:missing_field | 400 | El body no cumple el schema esperado o falta un campo requerido. |
auth:permission_denied | 403 | La API key no tiene el permiso requerido. |
auth:invalid_token | 401 | La API key es inválida o fue revocada. |
Siguientes pasos
- Preparación y Envío — prepare, fulfill y endpoints en lote
- Devoluciones y Reembolsos
- Adjuntos
- Transiciones de estado