Envíos (Envia.com)
Cotiza y genera guías de Coordinadora, Servientrega, TCC, Inter Rapidísimo y otras transportadoras desde un contacto, a través de tu cuenta de Envia.com. Esta página resume la API; el detalle de cada campo está en la referencia (sección Shipments).
Qué es
Un envío siempre sale de un contacto: el destino se toma de su dirección y ciudad, y lo que mandes en destination lo reemplaza. El origen es el que la organización configuró en la app (Ajustes → Envíos); no se envía por API. Estados: draft (se intentó generar y falló), created (guía generada, el único cancelable), picked_up, in_transit, out_for_delivery, delivered y los de excepción. El rastreo se actualiza solo por webhook y por una revisión periódica.
Requisitos
- • El módulo Envíos activo en el plan (sin él, 403
PLAN_MODULE_REQUIRED). - • La API key de Envia.com en Configuración → Integraciones, con saldo en esa cuenta.
- • La dirección de origen en Ajustes → Envíos.
- • Un token con
shipments:readpara cotizar y consultar, yshipments:writepara generar, rastrear y cancelar.
Endpoints y permisos
| Operación | Permiso | Qué hace |
|---|---|---|
| GET /shipments | shipments:read | Lista los envíos (filtros contactId y status; limit por defecto 20, máximo 100). |
| POST /shipments/rates | shipments:read | Cotiza en todas las transportadoras de tu cuenta. No escribe ni cobra. |
| POST /shipments | shipments:write | Genera la guía. Cobra saldo de tu cuenta de Envia. |
| GET /shipments/{id} | shipments:read | Consulta un envío con su estado y eventos. |
| POST /shipments/{id}/track | shipments:write | Refresca el rastreo contra Envia. |
| POST /shipments/{id}/cancel | shipments:write | Cancela una guía en estado created y devuelve el saldo si Envia lo informa. |
No hay borrado de envíos ni programación de recogidas por separado: la recogida se pide al generar (pickup).
Cotizar y generar
Primero cotiza: la respuesta trae rates ordenadas por precio y failed con las transportadoras que no respondieron (una caída no tumba la cotización). De la tarifa elegida tomas carrier y service.
1. Cotizar al contacto
curl -X POST "https://api.fusioncol.com/api/shipments/rates" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"contactId": "66c74b4f66baaf700d2f13e4",
"packages": [{ "content": "manillas", "weight": 1,
"dimensions": { "length": 20, "width": 15, "height": 10 }, "declaredValue": 50000 }]
}'2. Generar la guía (cobra saldo)
curl -X POST "https://api.fusioncol.com/api/shipments" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"contactId": "66c74b4f66baaf700d2f13e4",
"carrier": "serviEntrega",
"service": "premier",
"packages": [{ "content": "manillas", "weight": 1,
"dimensions": { "length": 20, "width": 15, "height": 10 }, "declaredValue": 50000 }],
"idempotencyKey": "pedido-4521-1"
}'Opcionales: destination (pisa lo del contacto), insurance, cod (contra entrega, si el servicio lo soporta), pickup y dealId/quotationId/invoiceId para vincular el envío. Pesos en kg y medidas en cm.
Idempotencia y cobro de saldo
Generar una guía cobra saldo de tu cuenta de Envia, y FusionCRM llama a Envia una sola vez por intento: nunca reintenta un generate por su cuenta. Para que tus reintentos no cobren dos veces, manda siempre idempotencyKey (1-100 caracteres, única en la organización):
- • Misma clave y el envío ya tiene guía → 200 con
reused: true, sin llamar a Envia (el body se ignora). - • Misma clave y el intento anterior falló (Envia rechazó la guía) → se vuelve a intentar sobre el mismo envío: 201 o de nuevo 422.
- • Misma clave con un generate en curso → 409
SHIPMENT_IN_PROGRESS. - • Resultado desconocido (timeout de 25 s, red, 5xx) → 409
SHIPMENT_NEEDS_REVIEW. La guía pudo cobrarse; ese envío nunca se regenera solo. Revisa el panel de Envia y usa una clave nueva solo si no se creó.
pedido-4521-1), no por pedido: para generar otra guía después de cancelar la anterior necesitas una clave nueva. Sin clave, la protección es solo best-effort (una ventana de 30 segundos por contacto).Ciudad del destino: 422 INVALID_CITY
La ciudad del destino se resuelve contra el catálogo DANE. Si el contacto ya tiene cityCode, se usa ese. Si no, o si mandas destination.city, tiene que ser inequívoca. Manda destination.cityCode (5 dígitos) para evitar dudas.
El error de Envíos no es el mismo que el CITY_UNRESOLVED de contactos: usa code: INVALID_CITY, reason (ambiguous, fuzzy, none o unsupported_country), input como objeto y candidatos con name, dane8 y la sigla de departamento de Envia (stateIso). Reenvía con el code del candidato como destination.cityCode.
422 INVALID_CITY
{
"success": false,
"code": "INVALID_CITY",
"message": "La ciudad \"Armenia\" es ambigua; indica el departamento o el cityCode.",
"reason": "ambiguous",
"input": { "city": "Armenia" },
"candidates": [
{ "code": "63001", "dane8": "63001000", "name": "Armenia", "stateCode": "63", "stateName": "Quindío" },
{ "code": "05059", "dane8": "05059000", "name": "Armenia", "stateCode": "05", "stateName": "Antioquia" }
]
}Solo se envía dentro de Colombia: un destino con otro país responde 422 INVALID_CITY con reason: unsupported_country.
Otros errores
Todos llevan success: false, code y message; los de Envia agregan error normalizado (nunca la respuesta cruda del proveedor).
| HTTP | code | Cuándo |
|---|---|---|
| 409 | SHIPMENT_IN_PROGRESS | Otro POST con la misma idempotencyKey (o del mismo contacto sin clave) está generando la guía. Espera unos segundos y reintenta con la misma clave. |
| 409 | SHIPMENT_NEEDS_REVIEW | No se sabe si Envia generó la guía (timeout, red). Pudo cobrarse: revisa el panel de Envia y, si hace falta, reintenta con una clave nueva. |
| 400 | IDEMPOTENCY_KEY_REUSED | Esa idempotencyKey ya se usó con otro contacto. |
| 422 | ENVIA_GENERATE_FAILED | Envia rechazó la guía (saldo insuficiente, transportadora caída…). Queda un borrador (shipmentId) que puedes reintentar con la misma clave. |
| 422 | ENVIA_NOT_CONFIGURED / ORIGIN_NOT_CONFIGURED | Falta la API key de Envia (Integraciones) o la dirección de origen (Ajustes → Envíos). |
| 409 | SHIPMENT_NOT_CANCELABLE / SHIPMENT_NOT_TRACKABLE | Solo se cancela un envío en created; un draft no tiene guía que rastrear. |
| 403 | PLAN_MODULE_REQUIRED | El plan de la organización no tiene el módulo Envíos. |
quote_shipment, create_shipment, track_shipment y list_contact_shipments.