CarrierAPI — Plataforma de envíos multitransportista autoalojada

Una sola API REST para etiquetas de envío, tarifas, seguimiento y envío por lotes con varios transportistas — autoalojada, como alternativa a una herramienta SaaS como SendCloud, con control total sobre los contratos propios con los transportistas.

Envíos multitransportista
FastAPI / Python
Sync NetSuite & Shopify
Autoalojado

Rol & alcance

Una empresa de comercio electrónico con su propio ERP (NetSuite) enviaba a través de una herramienta SaaS, con los costes y el control limitado sobre los contratos con transportistas que eso implica. CarrierAPI es el sustituto autoalojado: una API que crea etiquetas, compara tarifas, sigue envíos y procesa lotes con varios transportistas, con los mismos puntos de conexión que la herramienta anterior para que el cambio desde NetSuite pudiera ser un reemplazo directo en lugar de una reconstrucción.

  • Una arquitectura de adaptadores por transportista (PostNL, DHL Express y UPS como conjunto base; DHL Parcel, FedEx, GLS y el propio SendCloud como adaptadores adicionales), de modo que añadir un transportista no exige cambios en el resto del sistema.
  • Reemplazo directo de la herramienta SaaS anterior dentro de NetSuite: mismos nombres de campos personalizados, cambios mínimos en la integración SuiteScript existente.
  • Conexión directa con los registros Item Fulfillment de NetSuite, más sincronización con Shopify y una integración con Amazon junto a los transportistas.
  • Dos formas de gestionar las credenciales de transportista: desde la interfaz (respaldada por base de datos, la preferida) o mediante variables de entorno (vía heredada para despliegues existentes).

Impacto

  • Los costes de envío y los contratos con transportistas vuelven a estar en manos propias, en lugar de depender de las tarifas y condiciones de una capa SaaS intermedia.
  • Se reparó el reconocimiento de direcciones para una clase de direcciones que antes se analizaba mal (la extracción del número tomaba por error el último número en lugar del primero tras el nombre de la calle — incorrecto, por ejemplo, en direcciones de parques vacacionales con número de casa y número de chalé).
  • La conciliación de facturas con UPS siguió funcionando después de que UPS cambiara dos veces el formato de exportación de sus facturas, al basar la detección de columnas en el contenido en lugar de en posiciones fijas, contrastada con el importe total que la propia factura declara.
  • Se cerró una fuga de sesión por la que usuarios eliminados conservaban acceso hasta 24 horas, porque solo se comprobaban la firma y la caducidad de su token — no si la cuenta seguía existiendo.

Arquitectura

Cada transportista es un adaptador tras una interfaz común (crear y cancelar envíos, consultar tarifas, seguimiento, servicios disponibles) — conectar un transportista nuevo no toca el resto del sistema. El backend es FastAPI (Python, async) con PostgreSQL como base de datos principal y un worker en segundo plano sobre Redis (arq) para el procesamiento por lotes de etiquetas, de modo que crear cientos de etiquetas a la vez no bloquea la API. Las etiquetas se guardan en MinIO (compatible con S3), para que el almacenamiento no quede atado a un único proveedor cloud. El frontend es un panel Next.js/React para gestionar envíos, ajustes de transportistas y credenciales. Todo funciona autoalojado con Docker Compose tras Traefik, desplegado con Coolify.

Elección de modelo

Sin IA/LLM: este es deliberadamente un sistema determinista — las etiquetas, tarifas y seguimiento deben ser previsibles y auditables, no generados. La decisión clave aquí fue autoalojado frente a SaaS: una herramienta SaaS se pone en marcha antes, pero una plataforma autoalojada da control sobre los contratos con transportistas, elimina cualquier tarifa por etiqueta o por envío a una capa intermedia y permite construir funcionalidad (como la integración directa con NetSuite) exactamente a medida en vez de esperar a lo que un proveedor SaaS soporte o no.

Costes & latencia

  • Infraestructura autoalojada (Docker Compose, PostgreSQL, Redis, MinIO) en lugar de una tarifa SaaS recurrente por envío.
  • La generación de etiquetas por lotes corre de forma asíncrona sobre una cola Redis (arq), de modo que crear cientos de etiquetas a la vez mantiene la API receptiva en lugar de dejar esperando a quien la solicita.
  • La conciliación de facturas se verificó contra facturas reales de UPS: entre otras, una factura de 1.275 líneas por 4.855,72 € y una exportación de 2.275 líneas, ambas procesadas correctamente tras el arreglo en la detección de columnas.

Lecciones aprendidas

El análisis de direcciones neerlandesas fallaba en una clase concreta de direcciones (parques vacacionales con número de casa y un número de chalé aparte, como «Hessenweg 83 41») porque el parser leía el último número de la línea de calle como número de casa en lugar del primero tras el nombre de la calle. Resuelto con un parser compartido, verificado contra un caso real. La importación de facturas de UPS se rompió dos veces porque UPS cambió el formato de exportación de sus facturas (el número y el orden de columnas se desplazaron); el enfoque de posiciones fijas se sustituyó por detección de columnas basada en contenido, cuyo resultado se contrasta con el importe total que la propia factura declara. Los avisos de validación de dirección bloqueaban al principio por completo la creación de un envío; se rebajó a bloquear solo la compra automática de la etiqueta, de forma que un envío marcado sigue visible y se puede reintentar en lugar de quedarse atascado. Y una vulnerabilidad de sesión: los usuarios eliminados mantenían acceso hasta 24 horas porque los tokens solo se comprobaban por firma y caducidad, no por la existencia de la cuenta — resuelto verificando en cada petición que la cuenta sigue existiendo.