Documentación pública / partner Esta versión está pensada para clientes y socios que integran las API. Algunas secciones reservadas a administradores (gestión de usuarios, planes, detalles de infraestructura) no están incluidas.

URL Base y entornos

Los endpoints están versionados bajo /api/v1. Use siempre HTTPS.

Entorno URL Base Notas
Producción https://flow.icarry.it Conectado a la flota real y trabajos programados por iCarryUP.

En esta versión para socios no se muestran enlaces a Swagger ni ReDoc. El acceso a /api/docs, /api/redoc y /openapi.json está restringido solo a superadministradores (el resto recibe 403). Para socios, la referencia es el listado de endpoints de esta página.

Autenticación

La API utiliza tokens JWT con esquema Bearer. Obtenga el token enviando credenciales al endpoint OAuth2.

POST /api/v1/auth/token
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=OPS_USER&password=********

El token devuelto debe enviarse en el header:

Authorization: Bearer <ACCESS_TOKEN>

⚠️ Configure rotación de token server-side cada 24h o use refresh programados. Para integraciones server-to-server, cree usuarios técnicos dedicados (rol: system).

Flujo de trabajo recomendado

  1. Cargue datos logísticos (conductores + entregas) en el formato esperado por RoutingOptimizationRequest.
  2. Envíe POST /api/v1/routing/optimize con async_processing=true; reciba un job_id.
  3. Monitoree el estado vía GET /api/v1/routing/jobs/{job_id} (polling 5-10s) o vía WebSocket /ws/jobs.
  4. Cuando status=completed lea result, exporte archivos o genere mapas con los endpoints dedicados.
  5. Opcional: configure webhook_url en la solicitud para recibir callbacks push (payload idéntico a result).

Endpoints críticos

POST /api/v1/routing/optimize

Envía una nueva optimización. Soporta payloads modernos y legacy (conversión automática de lat/lng a start_lat, etc.).

{
  "async_processing": true,
  "session_id": "tms-session-example-001",
  "webhook_url": "https://your-tms.example.com/webhooks/routing",
  "delivery_points": [
    {
      "tracking_number": "SHIP-EXAMPLE-0001",
      "delivery_company": "Example SpA",
      "address": "Via Esempio 1, Milano",
      "lat": 45.4642,
      "lng": 9.1900,
      "tot_items": 4,
      "priority": 1
    }
  ],
  "drivers": [
    {
      "name": "Driver example 01",
      "start_lat": 45.5342,
      "start_lng": 9.3265,
      "end_lat": 45.5342,
      "end_lng": 9.3265,
      "capacity": 90,
      "vehicle_type": "van_standard",
      "max_distance_km": 220
    }
  ],
  "algorithms": ["standard"],
  "optimization_objective": "time",
  "optimization_params": {
    "max_iterations": 120,
    "time_limit_seconds": 420,
    
    "distance_weight": 0.5,
    "time_weight": 0.3,
    "balance_weight": 0.2
    
  },
  "constraints": {
    "max_route_distance": 250,
    "max_route_duration": 480,
    "max_stops_per_route": 45
  }
}

Respuesta inmediata:

{
  "job_id": "6b758bee-65e5-473e-add8-8cecc36f6fda",
  "status": "queued",
  "estimated_completion": "2025-11-26T09:11:37.123Z",
  "result_url": "/api/v1/routing/jobs/6b758bee-65e5-473e-add8-8cecc36f6fda"
}

GEL (recogida en locker): si el usuario no tiene la feature de plan gel_proximity (tenant con GEL en mapa + flag en tier/perfil), el backend elimina en silencio pickup_point_id de las entregas y gel_cost_to_time_equivalent_minutes_per_eur de optimization_params antes de optimizar.

Qué objetivo enviar

Los mismos cuatro valores del asistente de la consola. El campo es optimization_objective en POST /api/v1/routing/optimize. El predeterminado es time. Un valor desconocido se trata como time. Existen porque un solo número no puede ser a la vez el recorrido más corto, el más puntual y el más barato.

Menos tiempo time

Por quéSin este objetivo, un recorrido corto en km puede hacer esperar a los destinatarios. Penaliza la espera y llena las franjas horarias.

CuándoÚselo con SLA, ventanas estrechas o horas prometidas.

Menos km distance

Por quéCuando cuentan los kilómetros, no el reloj. La espera no se penaliza.

CuándoÚselo si dominan combustible y peajes, las paradas están dispersas o hay pocas franjas.

Equilibrado balanced

Por quéCompromiso entre tiempo y kilómetros, sin forzar un extremo.

CuándoÚselo con flota mixta o un día normal.

Menos costes cost

Por quéConvierte kilómetros y horas en euros con los campos del conductor: hourly_cost, fuel_consumption, prezzo_litro y costo_pedaggio_km.

CuándoÚselo para un presupuesto de flota o una comparación económica. budget_max_eur en optimization_params es el tope, no este objetivo.

No es balance_options: eso reparte la carga entre conductores (número de paradas, km o minutos parecidos). Los pesos distance_weight, time_weight y balance_weight en optimization_params son un ajuste fino; para la integración basta optimization_objective.

{
  "optimization_objective": "time"
}

Sustituya time por distance, balanced o cost. El resto de la petición optimize sigue como en el ejemplo.

GET /api/v1/routing/jobs/{job_id}

Devuelve estado, progreso y, si completado, el RoutingResultResponse completo (rutas, geometrías, métricas globales). Los resultados se persisten en caché compartida y se eliminan durante el mantenimiento programado.

En el resultado completado puede aparecer savings_report: ahorro estimado (km/tiempo/coste) frente a una baseline nearest-neighbor del mismo job.

GET /api/v1/routing/jobs

Lista los últimos jobs del usuario. Acepta ?limit=50 y ?status=processing/completed... para dashboards operativos.

DELETE /api/v1/routing/jobs/{job_id}

Cancela jobs en cola o en ejecución. Devuelve 400 si el job ya está completado.

GET /api/v1/routing/eta

Estima la duración wall-clock de la optimización (segundos) a partir de runs históricos similares (P50/OLS) o del presupuesto TSP. Query típicas: deliveries, drivers, algorithm, routing_provider, has_time_windows, pickup_count, optimization_objective.

GET /api/v1/routing/history

Historial persistente de optimizaciones del usuario/tenant (excluye simulaciones si se solicita). Admite q= para buscar por nombre o job_id. Útil para dashboards y auditoría.

GET /api/v1/routing/calendar

Eventos de calendario (runs planificados y borradores) para un intervalo de fechas. Alimenta la vista calendario de la consola.

GET /api/v1/routing/status

Health-check enriquecido (jobs activos, versión, uptime). Puede usarse para sistemas de monitoreo o readiness probes.

El campo algorithms_available está reservado a cuentas administrativas; para el resto es siempre un array vacío.

POST /api/v1/routing/simulate

Inicia una simulación what-if (Control Tower) a partir de un job baseline. Devuelve un simulation_id; el resultado es un job de optimización con is_simulation=true.

{
  "baseline_job_id": "6b758bee-65e5-473e-add8-8cecc36f6fda",
  "baseline_scope": "PLANNED",
  "simulation_mode": "reoptimize",
  "patches": [
    {
      "type": "add_delivery",
      "point_type": "delivery",
      "lat": 41.9028,
      "lng": 12.4964,
      "tracking_number": "NEW-001",
      "pickup_point_id": "HUB-1"
    },
    { "type": "remove_delivery", "tracking_number": "OLD-042" }
  ]
}

Parches soportados: add_delivery (también recogidas con point_type=pickup y pickup_point_id), remove_delivery, add_driver, remove_driver, delivery_time_window, balance_options, invalidate_matrices. baseline_scope=PLANNED (LIVE no soportado en v1).

GET /api/v1/routing/simulations/{simulation_id}

Devuelve metadatos y comparación de la simulación (baseline vs resultado what-if).

POST /api/v1/routing/estimate-workload

Estima la carga de trabajo (minutos/conductores) antes de elegir la flota. mode=quick (heurística rápida) o precise (solver con flota virtual).

GET /api/v1/routing/delivery-execution/summary

KPI de ejecución de entregas (p. ej. puntualidad %) agregado sobre los últimos jobs del usuario.

GET /api/v1/routing/jobs/{job_id}/delivery-execution

Detalle de ejecución de entregas y prueba de entrega (POD) para un job concreto.

POST /api/v1/routing/manual-assignments

Permite fijar entregas → conductor antes de lanzar la optimización. Los endpoints GET/DELETE /manual-assignments permiten leer/reiniciar preferencias.

POST /api/v1/routing/jobs/{job_id}/generate-real-map

Crea mapas HTML persistentes (carpeta web/static/maps) listos para distribución a conductores. GET .../download-map y GET .../export generan mapas y Excel respectivamente.

POST /api/v1/routing/jobs/{job_id}/generate-geometries

Genera geometrías de carretera para un job completado (JWT obligatorio). Header opcional If-Match con routes_version_hash; mismatch → 409 routes_version_mismatch — reintentar sin header (las geometrías vienen del job guardado).

GET /api/v1/routing/driver-maps

Lista mapas de conductores del tenant actual (JWT obligatorio; 401 sin token). Superusuario sin impersonación puede ver todos los tenants.

Geocoding (autenticado)

JWT obligatorio. POST /optimize no geocodifica: lat/lng numéricos en el JSON siguen siendo obligatorios. Llame antes a estos endpoints. source es una etiqueta de diagnóstico, no un contrato.

POST /api/v1/geocoding/lookup

Solo caché, máximo 500 direcciones. hit false = no está en caché (use forward). No inicia una resolución externa.

{
  "addresses": ["Via Roma 1, Milano", "Piazza Duomo, Firenze"]
}
{
  "results": [
    { "index": 0, "hit": true, "lat": 45.46, "lng": 9.19, "source": "…", "low_confidence": false, "cache_id": 12 },
    { "index": 1, "hit": false, "lat": null, "lng": null, "source": null, "low_confidence": null, "cache_id": null }
  ]
}

POST /api/v1/geocoding/forward

Resuelve hasta 10 direcciones (raw + query). origin: api (por defecto), wizard, mobile, one_driver, simulator, rubrica. Presupuesto de unos 25 segundos. status: ok, not_found, pending (repita la misma llamada), error.

{
  "origin": "api",
  "items": [{ "raw": "Via Roma 1, Milano", "query": "Via Roma 1, Milano" }]
}
{
  "results": [
    {
      "status": "ok",
      "lat": 45.46,
      "lng": 9.19,
      "confidence": 90,
      "matched": true,
      "low_confidence": false,
      "source": "…",
      "cache_id": 12
    }
  ]
}

GET /api/geocode_address?address=

Una sola dirección, el mismo resolver que forward. 200 con lat/lng; 400 si falta address; 404 si no hay resultado; 503 si la resolución sigue pending.

GET /api/reverse_geocode?lat=&lng=

De coordenadas a dirección. 200 { address, source }; 400 si falta lat o lng; 404 si no hay resultado.

Pines de coordenadas Enterprise

Plan Enterprise: guarda direcciones y coordenadas. Los pines del tenant tienen prioridad en lookup/forward. Captura opcional desde POST /optimize.

POST /api/v1/geocoding/pins

Upsert de hasta 500 pines. Mismo rol que DELETE y PUT settings: owner, admin o superuser, además de la feature geocode_pins. Un member recibe 403 owner_or_admin_required. Cada elemento de results tiene index, status, pin_id, address_key, error.

status: created (nuevo), updated (misma dirección, coordenadas movidas al menos 5 m), unchanged (movimiento inferior a 5 m), rejected (error: invalid_address, invalid_coordinates, zero_coordinates, swapped_lat_lng, out_of_area), limit_reached (tope de pines del tenant). summary usa los mismos conteos.

address_key usa la misma normalización que lookup y forward: Unicode NFKC, minúsculas, espacios comprimidos, comas como «, », espacios y comas de los extremos eliminados, máximo 500 caracteres. La misma cadena en POST y en lookup encuentra el pin: use el valor devuelto. Cambian la clave el número, el código postal o palabras extra; no la cambian mayúsculas ni espacios dobles.

{
  "items": [
    { "address": "Via Roma 1, 20121 Milano MI", "lat": 45.46, "lng": 9.19, "external_id": "CLI-1" }
  ]
}
{
  "results": [
    { "index": 0, "status": "created", "pin_id": 12, "address_key": "via roma 1, 20121 milano mi", "error": null }
  ],
  "summary": { "created": 1, "updated": 0, "unchanged": 0, "rejected": 0, "limit_reached": 0 }
}

GET /api/v1/geocoding/pins

Lista de pines para quien tenga la feature (q desde 3 caracteres, external_id, limit, after_id).

DELETE /api/v1/geocoding/pins/{pin_id}

Elimina un pin del propio tenant. Solo owner, admin o superuser. El pin de otro tenant responde 404.

GET / PUT /api/v1/geocoding/pins/settings

GET (feature): enabled, auto_capture, count, max_pins. PUT (owner/admin): cuerpo obligatorio { "auto_capture": true|false }. Respuesta PUT: enabled, auto_capture, max_pins.

{ "auto_capture": true }

Exportación Excel (autenticada)

POST /api/v1/routing/export-geocoded-deliveries

Requiere Authorization Bearer. Devuelve un archivo Excel a partir del payload enviado.

POST /api/v1/routing/export-geocoded-drivers

Requiere Authorization Bearer. Devuelve un archivo Excel a partir del payload enviado.

POST /api/v1/routing/export-manual-drivers

Requiere Authorization Bearer. Devuelve un archivo Excel a partir del payload enviado.

POST /api/v1/routing/export-manual-deliveries

Requiere Authorization Bearer. Devuelve un archivo Excel a partir del payload enviado.

POST /api/v1/routing/export-manual-pickups

Requiere Authorization Bearer. Devuelve un archivo Excel a partir del payload enviado.

Endpoints públicos / bootstrap

GET /api/v1/public/features

Devuelve flags de frontend: gel_proximity_enabled, rlp_bryntum_timeline_enabled y bootstrap PostHog (posthog_enabled, posthog_host, posthog_project_api_key, posthog_session_replay, posthog_unmask_replay). Bearer opcional: sin token GEL es false; con token se evalúan tenant y tier. Si PostHog está deshabilitado o incompleto, posthog_enabled es false y no se expone la project key.

GET /api/v1/public/fuel-prices

Medias de combustible y energía, sin autenticación. No es una serie temporal de iCarry: instantánea actual de MIMIT (medias diarias de Italia y por región) más GNL/HVO de estaciones y recarga pública AC/DC mensual. Para UI y estimaciones de coste, no para facturación y sin SLA sobre fuentes de terceros. No es el campo prezzo_litro de la ruta.

Cache-Control public, max-age=1800: respetar ese TTL al consultar. national y regions: gasóleo, gasolina y GLP en €/L, metano en €/kg (regions[].name es el nombre de región MIMIT, p. ej. Lombardia). extended.gnl (eur_kg), hvo (eur_l), electric_ac/electric_dc (eur_kwh) con value, unit, updated, source. Si fallan todas las fuentes: {"available": false}. El PUN de GME no está incluido. El JSON de ejemplo muestra la forma, no valores en vivo.

{
  "available": true,
  "source": "MIMIT",
  "updated": "21/09/2026",
  "national": { "gasolio": 1.623, "benzina": 1.712, "gpl": 0.741, "metano": 1.401 },
  "regions": [{ "name": "Lombardia", "gasolio": 1.631, "benzina": 1.720, "gpl": 0.738, "metano": 1.390 }],
  "extended": {
    "gnl": { "value": 1.452, "unit": "eur_kg", "source": "mimit_impianti" },
    "hvo": { "value": 1.890, "unit": "eur_l", "source": "mimit_impianti" },
    "electric_ac": { "value": 0.62, "unit": "eur_kwh", "source": "adiconsum_mensile" }
  }
}

El endpoint de puntos de recogida GEL en mapa no forma parte de esta documentación pública para partners. Está en la documentación interna (superadmin) y se facilita bajo demanda si el contrato incluye integración locker. Contacte a soporte.

Diccionario de datos de entrada (Excel/CSV ↔ JSON)

Las columnas oficiales de las plantillas se mapean a los campos de POST /api/v1/routing/optimize. Descargue plantillas en blanco y envíe JSON geocodificado. El orden de columnas está definido en las plantillas de entregas y conductores.

Plantillas: GET /api/v1/templates/delivery-template y GET /api/v1/templates/driver-template (XLSX/CSV). No hay descarga de pickup aparte: use la hoja de entregas con point_type=pickup.

En Excel lat/lng pueden omitirse si la dirección es geocodificable. POST /optimize siempre exige lat/lng numéricos (y start_lat/start_lng para conductores).

POST /api/v1/files/upload es solo almacenamiento: no analiza columnas ni ejecuta la optimización. La integración API de partners es JSON hacia /optimize.

Entregas / paradas (delivery_points[])

Excel JSON /optimize Oblig. Tipo Uso
tracking_numbertracking_numbersícadena ≤64ID de parada
delivery_addressaddresssí (o lat+lng)cadenaGeocodificación / visualización
delivery_companydelivery_companysí en JSON (import por defecto “Cliente”)cadenaMetadato
lat / lnglat / lngsí en JSON; opcional en Excel si hay direccióngradosMatriz / geometría
tot_itemstot_itemsno (por defecto 1)int ≥1Capacidad (bultos)
prioritypriorityno (por defecto 1)1–10 (1 = alta)Prioridad / drop
estimated_durationestimated_durationnominutosTiempo de servicio
notesnotesnocadena ≤500Solo app del conductor
phonephonenoE.164 (+ y dígitos, p. ej. +393331234567)Teléfono del destinatario (enlace tel en app y Control Tower)
preassigned_driverpreassigned_drivernodrivers[].nameLock → mandatory_assignments
point_typepoint_typeno (por defecto delivery)pickup | deliveryOrden recogida→entrega; recogida sin enlace = parada autónoma
pickup_point_idpickup_point_idnocadenaEnlace entrega→recogida; si falta, la mercancía vuelve al punto de llegada
time_window_start / endigualnoHH:MMVentanas horarias
volume_m3 / weight_kgigualnofloat ≥0Tope de volumen (peso → 0.001 m³ si falta volumen)

Solo JSON (parada): id opcional (si no, tracking_number o UUID generado).

Un point_type=pickup sin entrega vinculada no se descarta: es una parada obligatoria y la mercancía vuelve al punto de llegada del conductor. La respuesta pone pickup_mode=return_to_depot y una fila en warnings. Si no se puede planificar aparece en unassigned_deliveries.

Conductores / vehículos (drivers[])

Excel JSON /optimize Oblig. Notas
namenamesíIdentidad
phonephonenoTeléfono del conductor opcional en E.164
start_address / end_address—start obligatorio en importGeocodificación → start_* / end_*
lat / lngstart_lat / start_lngsí en JSONDepósito de salida
end_lat / end_lngend_lat / end_lngsí en JSON (por defecto = start)Retorno
capacitycapacityno (por defecto 50)Máx. bultos (tot_items)
max_volume_m3max_volume_m3noCapacidad de volumen
vehicle_typevehicle_typeno (por defecto car)Lista completa abajo: car, van, van_standard, van_maxi, truck, truck_7_5t, truck_12t, truck_18t, truck_32t, artic_44t, bike, scooter, icarry_cargo_bike
routing_profilerouting_profilenoOverride: car, van_standard, van_maxi, truck_7_5t, truck_12t, truck_18t, truck_32t, artic_44t, icarry_cargo_bike
max_distance_kmmax_distance_kmnoTope de km
hourly_cost, fuel_consumption, prezzo_litro, costo_pedaggio_kmigualnoCostes / informes
start_time / end_timeigualno (08:00–18:00 si hay par)Turno
break_start / break_endigualen parejaPausa
max_minutesmax_minutesnoDuración máx. (derivable de turno−pausa)

Solo JSON (conductor): id opcional, active (por defecto true), max_overtime_minutes (por defecto 0).

Tipos de vehículo admitidos (lista completa)

Se envía un slug, no el modelo comercial. Predeterminado vehicle_type=car. El 4x4 o la carrocería no tienen slug propio.

Slug API Categoría Cuándo usarlo
carTurismo (M1)Turismo estándar.
van AliasFurgones (N1)Igual que van_standard.
van_standardFurgones (N1)Furgón compacto hasta 2,5 t, altura unos 1,9 m.
van_maxiFurgones (N1)Furgón techo alto hasta 3,5 t, altura unos 2,7 m.
truck AliasCamionesIgual que truck_7_5t.
truck_7_5tCamionesCamión ligero urbano, MMA 7,5 t.
truck_12tCamionesCamión medio, MMA 12 t. Ejemplo: Iveco TGM 13.250 4x4 → truck_12t.
truck_18tCamionesCamión pesado de 2 ejes, MMA 18 t.
truck_32tCamionesCamión de 4 ejes, MMA 32 t.
artic_44tArticuladosArticulado 44 t, unos 16,5 m.
bike AliasCiclo-logísticaIgual que icarry_cargo_bike.
scooter AliasTurismo (M1)Igual que car.
icarry_cargo_bikeCiclo-logísticaBicicleta de carga de última milla.

Si se envía, routing_profile debe ser un slug vial de la tabla (no un alias van/truck/bike/scooter) y tiene prioridad sobre vehicle_type.

Alias de cabecera frecuentes (IT/EN)

La importación también acepta cabeceras alternativas (normalizadas, sin acentos). Ejemplos frecuentes:

Esquema de datos principal

DeliveryPointRequest

Obligatorios en JSON: lat/lng, tracking_number (≤64), address, delivery_company. Opcionales: tot_items (default 1), priority (1–10), estimated_duration (minutos), notes, phone (E.164, p. ej. +393331234567), preassigned_driver, point_type (pickup|delivery), pickup_point_id, time_window_start/end (HH:MM), volume_m3, weight_kg, id.

Mapa completo Excel↔JSON: ver «Diccionario de datos de entrada» arriba.

DriverRequest

Obligatorios en JSON: name, start_lat/lng, end_lat/lng (end por defecto = start). Opcionales: phone (E.164), capacity (default 50), max_volume_m3, vehicle_type (default car), routing_profile, max_distance_km, costes, start_time/end_time, break_start/end, max_minutes, active, max_overtime_minutes, id. Solo Excel: start_address/end_address.

vehicle_type — lista completa: car, van, van_standard, van_maxi, truck, truck_7_5t, truck_12t, truck_18t, truck_32t, artic_44t, bike, scooter, icarry_cargo_bike. Por defecto car. No se envía marca o modelo: un Iveco TGM 13.250 4x4 es truck_12t. Alias: van → van_standard, truck → truck_7_5t, bike → icarry_cargo_bike, scooter → car.

routing_profile — override opcional. Valores permitidos: car, van_standard, van_maxi, truck_7_5t, truck_12t, truck_18t, truck_32t, artic_44t, icarry_cargo_bike. Si se omite se deriva de vehicle_type.

Mapa completo Excel↔JSON: ver «Diccionario de datos de entrada» arriba.

OptimizationParamsRequest

Equilibra distancia, tiempo y carga con pesos configurables. Los valores dependen de las prioridades operativas.

RoutingConstraintsRequest

Activa restricciones hard (duración máxima, distancia máxima, paradas por ruta). Si no se definen, el motor aplica límites dinámicos según los conductores.

Webhook de completado

Configure webhook_url en la solicitud para recibir una POST firmada (header X-iCarry-Signature) con el mismo payload que RoutingResultResponse. Si el webhook devuelve código < 300 se considera entregado; si no, 3 reintentos exponenciales (15s, 60s, 180s).

Tiempo real vía WebSocket

Conéctese a wss://flow.icarry.it/ws/jobs y únase a la sala job_{job_id} vía evento Socket.IO join_room. Recibirá eventos job_progress, job_completed, job_failed.

Herramientas de soporte

Errores y mejores prácticas

Código Escenario Cómo reaccionar
400 Error de validación (esquema Pydantic) Lea detail para campo erróneo; aplique sanitización en el llamador.
401 Token faltante o expirado (también driver-maps / export Excel sin Bearer) Regenere token y repita la llamada.
403 Valor algorithms no permitido (use auto o standard) Use auto o standard, o contacte soporte.
403 Endpoint admin/superusuario sin privilegios Los endpoints de admin de tenant requieren is_admin; mutaciones de billing/algoritmos y settings requieren is_superuser.
409 Job duplicado en cola (mismo session_id) Use sesiones únicas para jobs paralelos.
409 routes_version_mismatch (If-Match / edición concurrente de rutas) Recargue el hash del job, o reintente generate-geometries sin If-Match.
503 Dependencia no configurada (p. ej. token webhook GEL ausente) Configure el token/secreto requerido en admin settings o env y reintente.
500 Error interno / Servicio de routing no disponible Reintento con backoff. Verifique estado con /api/v1/routing/status.

Para reducir tiempos de respuesta configure lotes entre 80 y 120 entregas por job; más de 150 paradas considere fraccionamiento automático (flag allow_partial_assignments true) y recomposiciones posteriores.

Soporte

Para funcionalidades avanzadas (motor high-performance, SLA prioritario, entornos dedicados) o para activar IP whitelisting en endpoints de producción, contacte [email protected] indicando su client_id y la IP pública a autorizar.

🚀 Guía de integración TMS (Transport Management System)

Esta guía resume cómo integrar las APIs de routing y optimización de iCarryUP con su TMS mediante llamadas servidor a servidor (sin interfaz web). La versión completa en italiano, con ejemplos de código extensos, está en Italiano.

Índice rápido

1. Introducción

API versionada bajo /api/v1. Flujo típico: su TMS envía conductores y paradas → iCarryUP optimiza → usted consulta GET /routing/jobs/{id} o recibe webhook en webhook_url → importa las rutas al TMS.

2. Configuración

2.1 Credenciales

Solicite un usuario técnico a [email protected] (roles, lista blanca de IP si aplica).

2.2 URL base

Entorno URL base Uso
Producción https://flow.icarry.it Tráfico real

2.3 Comprobación de conectividad

curl -s "https://flow.icarry.it/api/v1/routing/status"

Campos de ejemplo: status, version (p. ej. 2.9.23-1), active_jobs, routing_service_status. Sin auth para comprobar alcance. El campo algorithms_available está reservado a cuentas administrativas; para el resto es siempre [].

2.4 API pública y capa GEL en mapa

Use GET /api/v1/public/features para saber si aplican funciones GEL a su integración (igual que Endpoints públicos arriba). Bearer opcional; con token válido se evalúan mapa del tenant y gel_proximity en perfil/tier.

Documentación partner: el endpoint de listado de puntos GEL no está en esta página pública (interno/superadmin, bajo demanda). Contacte a [email protected].

En POST /api/v1/routing/optimize puede usar pickup_point_id por parada y gel_cost_to_time_equivalent_minutes_per_eur en optimization_params. Si el usuario del token no tiene gel_proximity efectivo, la API elimina silenciosamente esos campos antes de resolver — compruebe flags/tier antes de depender del GEL en optimización.

3. Autenticación

Grant tipo contraseña OAuth2 para obtener JWT; luego Authorization: Bearer <token>.

curl -X POST "https://flow.icarry.it/api/v1/auth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&username=USER&password=SECRET"

Renueve antes del vencimiento (a menudo ~24h). Prefiera usuarios técnicos para flujos servidor a servidor.

4. Flujo completo

  1. Mapee paradas/conductores del TMS a RoutingOptimizationRequest (esquema principal en esta página).
  2. Si faltan lat/lng, resuelva direcciones con POST /api/v1/geocoding/forward (o lookup solo si ya están en caché). POST /optimize sigue exigiendo coordenadas numéricas. Véase Geocoding.
  3. Opcional (Enterprise): sincronice sus pines con POST /api/v1/geocoding/pins para que las consultas posteriores reutilicen sus coordenadas. También puede activar la captura automática desde POST /optimize en /api/v1/geocoding/pins/settings.
  4. POST /api/v1/routing/optimize con async_processing: true → recibe job_id.
  5. Consulte GET /api/v1/routing/jobs/{job_id} cada 5–10s o use websocket/webhook.
  6. Cuando status sea completed, lea result; exporte mapas/Excel con los endpoints dedicados si hace falta.

5. Ejemplo mínimo de optimize

curl -X POST "https://flow.icarry.it/api/v1/routing/optimize" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "async_processing": true,
    "session_id": "tms-2026-04-02-001",
    "delivery_points": [{"tracking_number":"1","delivery_company":"ACME","address":"Via Roma 1, Milano","lat":45.46,"lng":9.19,"tot_items":1,"priority":1}],
    "drivers": [{"name":"Driver 1","start_lat":45.46,"start_lng":9.19,"end_lat":45.46,"end_lng":9.19,"capacity":50,"vehicle_type":"van_standard","max_distance_km":200}],
    "algorithms": ["standard"],
    "optimization_objective": "time"
  }'

Por qué existen time, distance, balanced y cost: guía de elección.

6. Webhooks

Defina webhook_url en la petición de optimize para recibir un POST con la misma forma que el resultado del job completado. Verificación opcional con X-iCarry-Signature. Reintentos con backoff si falla la entrega.

7. Buenas prácticas

8. Soporte

Al escribir a [email protected], incluya id de job, estado HTTP, payload anonimizado y marcas de tiempo.