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
- Cargue datos logísticos (conductores + entregas) en el formato esperado por
RoutingOptimizationRequest. - Envíe POST /api/v1/routing/optimize con async_processing=true; reciba un job_id.
- Monitoree el estado vía GET /api/v1/routing/jobs/{job_id} (polling 5-10s) o vía WebSocket /ws/jobs.
- Cuando status=completed lea result, exporte archivos o genere mapas con los endpoints dedicados.
- 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_number | tracking_number | sí | cadena ≤64 | ID de parada |
delivery_address | address | sí (o lat+lng) | cadena | Geocodificación / visualización |
delivery_company | delivery_company | sí en JSON (import por defecto “Cliente”) | cadena | Metadato |
lat / lng | lat / lng | sí en JSON; opcional en Excel si hay dirección | grados | Matriz / geometría |
tot_items | tot_items | no (por defecto 1) | int ≥1 | Capacidad (bultos) |
priority | priority | no (por defecto 1) | 1–10 (1 = alta) | Prioridad / drop |
estimated_duration | estimated_duration | no | minutos | Tiempo de servicio |
notes | notes | no | cadena ≤500 | Solo app del conductor |
phone | phone | no | E.164 (+ y dígitos, p. ej. +393331234567) | Teléfono del destinatario (enlace tel en app y Control Tower) |
preassigned_driver | preassigned_driver | no | drivers[].name | Lock → mandatory_assignments |
point_type | point_type | no (por defecto delivery) | pickup | delivery | Orden recogida→entrega; recogida sin enlace = parada autónoma |
pickup_point_id | pickup_point_id | no | cadena | Enlace entrega→recogida; si falta, la mercancía vuelve al punto de llegada |
time_window_start / end | igual | no | HH:MM | Ventanas horarias |
volume_m3 / weight_kg | igual | no | float ≥0 | Tope 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 |
|---|---|---|---|
name | name | sí | Identidad |
phone | phone | no | Teléfono del conductor opcional en E.164 |
start_address / end_address | — | start obligatorio en import | Geocodificación → start_* / end_* |
lat / lng | start_lat / start_lng | sí en JSON | Depósito de salida |
end_lat / end_lng | end_lat / end_lng | sí en JSON (por defecto = start) | Retorno |
capacity | capacity | no (por defecto 50) | Máx. bultos (tot_items) |
max_volume_m3 | max_volume_m3 | no | Capacidad de volumen |
vehicle_type | vehicle_type | no (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_profile | routing_profile | no | Override: car, van_standard, van_maxi, truck_7_5t, truck_12t, truck_18t, truck_32t, artic_44t, icarry_cargo_bike |
max_distance_km | max_distance_km | no | Tope de km |
hourly_cost, fuel_consumption, prezzo_litro, costo_pedaggio_km | igual | no | Costes / informes |
start_time / end_time | igual | no (08:00–18:00 si hay par) | Turno |
break_start / break_end | igual | en pareja | Pausa |
max_minutes | max_minutes | no | Duració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 |
|---|---|---|
car | Turismo (M1) | Turismo estándar. |
van Alias | Furgones (N1) | Igual que van_standard. |
van_standard | Furgones (N1) | Furgón compacto hasta 2,5 t, altura unos 1,9 m. |
van_maxi | Furgones (N1) | Furgón techo alto hasta 3,5 t, altura unos 2,7 m. |
truck Alias | Camiones | Igual que truck_7_5t. |
truck_7_5t | Camiones | Camión ligero urbano, MMA 7,5 t. |
truck_12t | Camiones | Camión medio, MMA 12 t. Ejemplo: Iveco TGM 13.250 4x4 → truck_12t. |
truck_18t | Camiones | Camión pesado de 2 ejes, MMA 18 t. |
truck_32t | Camiones | Camión de 4 ejes, MMA 32 t. |
artic_44t | Articulados | Articulado 44 t, unos 16,5 m. |
bike Alias | Ciclo-logística | Igual que icarry_cargo_bike. |
scooter Alias | Turismo (M1) | Igual que car. |
icarry_cargo_bike | Ciclo-logística | Bicicleta 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:
- Entregas: address/delivery_address ← indirizzo, destinazione, location · delivery_company ← destinatario, cliente, company · tot_items ← colli, quantity, pezzi · phone ← telefono, tel, cellulare, mobile · time_window_start/end ← fascia_dalle/alle, dalle/alle, window_start/end.
- Conductores: name ← nome, autista, fattorino · start_address/end_address ← partenza/rientro, departure/arrival · capacity ← capacita, max_consegne · start_time/end_time ← turno_inizio/fine, shift_start/end.
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
- Plantillas CSV/XLSX — GET /api/v1/templates/driver-template y /api/v1/templates/delivery-template. Diccionario de columnas: ver «Diccionario de datos de entrada» en esta página.
- Mapas conductor — GET /api/v1/routing/driver-maps lista mapas del tenant (JWT). Las URL HTML de un mapa concreto siguen siendo capability links.
- Driver App HTML — GET /api/v1/routing/jobs/{job_id}/download-driver-app?driver_name={driver_name} devuelve la versión offline del mapa de conductor único.
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.
- Automatización — lotes diarios o reoptimización bajo demanda.
- Fiabilidad — trabajos asíncronos, reintentos en webhooks, salud vía
/routing/status.
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.
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
- Mapee paradas/conductores del TMS a
RoutingOptimizationRequest(esquema principal en esta página). - Si faltan lat/lng, resuelva direcciones con
POST /api/v1/geocoding/forward(olookupsolo si ya están en caché).POST /optimizesigue exigiendo coordenadas numéricas. Véase Geocoding. - Opcional (Enterprise): sincronice sus pines con
POST /api/v1/geocoding/pinspara que las consultas posteriores reutilicen sus coordenadas. También puede activar la captura automática desdePOST /optimizeen/api/v1/geocoding/pins/settings. POST /api/v1/routing/optimizeconasync_processing: true→ recibejob_id.- Consulte
GET /api/v1/routing/jobs/{job_id}cada 5–10s o use websocket/webhook. - Cuando
statussea completed, learesult; 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
- Lotes de unas 80–120 paradas por job cuando sea posible; divida instancias muy grandes.
- Use
session_idúnicos para evitar conflictos 409. - Ante 401 renueve el token; 403 puede indicar algoritmo bloqueado o falta de permisos admin.
- Supervise
/routing/statusy los errores de job para la salud de la integración.
8. Soporte
Al escribir a [email protected], incluya id de job, estado HTTP, payload anonimizado y marcas de tiempo.