Base URL et environnements
Les endpoints sont versionnés sous /api/v1. Utilisez toujours HTTPS.
| Environnement | Base URL | Notes |
|---|---|---|
| Production | https://flow.icarry.it |
Connecté à la flotte réelle et aux jobs planifiés par iCarryUP. |
Dans cette version (partenaires), les liens vers Swagger et ReDoc ne sont pas affichés. L'accès à /api/docs, /api/redoc et /openapi.json est réservé aux seuls superadmins (les autres comptes reçoivent un 403). Pour les partenaires, la liste des endpoints de cette page fait foi.
Authentification
L'API utilise des jetons JWT avec le schéma Bearer. Obtenez le jeton en envoyant les identifiants à l'endpoint token OAuth2.
POST /api/v1/auth/token
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=OPS_USER&password=********
Le jeton renvoyé doit être envoyé dans l'en-tête :
Authorization: Bearer <ACCESS_TOKEN>
⚠️ Mettez en place une rotation des jetons côté serveur toutes les 24 h ou utilisez des rafraîchissements programmés. Pour les intégrations serveur à serveur, il est recommandé de créer des utilisateurs techniques dédiés (rôle : system).
Workflow recommandé
- Chargez les données logistiques (drivers + livraisons) au format prévu par
RoutingOptimizationRequest. - Envoyez POST /api/v1/routing/optimize avec async_processing=true ; vous recevez un job_id.
- Surveillez l'état via GET /api/v1/routing/jobs/{job_id} (polling 5-10 s) ou via WebSocket /ws/jobs.
- Lorsque status=completed, lisez result, exportez les fichiers ou générez des cartes avec les endpoints dédiés.
- Optionnel : définissez webhook_url dans la requête pour recevoir un callback push (payload identique à result).
Endpoints critiques
POST /api/v1/routing/optimize
Soumet une nouvelle optimisation. Prend en charge les payloads modernes et legacy (conversion automatique de lat/lng en 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
}
}
Réponse immédiate :
{
"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 (pickup locker) : si l'utilisateur n'a pas la fonctionnalité de plan gel_proximity (tenant avec GEL sur carte + flag sur le tier/profil), le backend retire silencieusement pickup_point_id des livraisons et gel_cost_to_time_equivalent_minutes_per_eur de optimization_params avant l'optimisation.
Quel objectif choisir
Les quatre mêmes valeurs que dans l'assistant de la console. Le champ est optimization_objective sur POST /api/v1/routing/optimize. La valeur par défaut est time. Une valeur inconnue est traitée comme time. Ils existent parce qu'un seul chiffre ne peut pas être à la fois la tournée la plus courte, la plus ponctuelle et la plus économique.
Moins de temps time
PourquoiSans cet objectif, une tournée courte en km peut faire attendre les destinataires. Pénalise l'attente et remplit les créneaux horaires.
QuandUtilisez-le avec des SLA, des fenêtres serrées ou des promesses horaires.
Moins de km distance
PourquoiUtile lorsque le kilométrage compte, pas l'horloge. L'attente n'est pas pénalisée.
QuandUtilisez-le si carburant et péages dominent, zones dispersées ou peu de créneaux horaires.
Équilibré balanced
PourquoiCompromis entre temps et kilomètres, sans pousser un extrême.
QuandUtilisez-le pour une flotte mixte ou une journée normale.
Moins de coûts cost
PourquoiConvertit kilomètres et heures en euros avec les champs du driver : hourly_cost, fuel_consumption, prezzo_litro, costo_pedaggio_km.
QuandUtilisez-le pour un budget de flotte ou une comparaison économique. budget_max_eur dans optimization_params est le plafond, pas cet objectif.
Ce n'est pas balance_options : celui-ci répartit la charge entre les livreurs (même nombre d'arrêts, km ou minutes). Les poids distance_weight, time_weight et balance_weight dans optimization_params sont un réglage fin ; pour l'intégration, optimization_objective suffit.
{
"optimization_objective": "time"
}
Remplacez time par distance, balanced ou cost. Les autres champs de la requête restent ceux de l'exemple optimize.
GET /api/v1/routing/jobs/{job_id}
Renvoie l'état, la progression et, s'il est terminé, l'ensemble du RoutingResultResponse (itinéraires, géométries, métriques globales). Les résultats sont persistés en cache partagé et supprimés lors de la maintenance programmée.
Dans le résultat terminé, le champ savings_report peut être présent : estimation d'économie (km/temps/coût) par rapport à une baseline nearest-neighbor sur le même job.
GET /api/v1/routing/jobs
Liste les derniers jobs de l'utilisateur courant. Accepte ?limit=50 et ?status=processing/completed... pour mettre en place des tableaux de bord opérationnels.
DELETE /api/v1/routing/jobs/{job_id}
Annule un job en file d'attente ou en cours d'exécution. Si le travail est déjà terminé, renvoie une erreur 400.
GET /api/v1/routing/eta
Estime la durée wall-clock de l'optimisation (secondes) à partir de runs historiques similaires (P50/OLS) ou du budget TSP. Requêtes typiques : deliveries, drivers, algorithm, routing_provider, has_time_windows, pickup_count, optimization_objective.
GET /api/v1/routing/history
Historique des optimisations persistantes de l'utilisateur/tenant (exclut les simulations si demandé). Prend en charge q= pour rechercher par nom ou job_id. Utile pour les tableaux de bord et l'audit.
GET /api/v1/routing/calendar
Événements calendrier (runs planifiés et brouillons) pour un intervalle de dates. Alimente la vue calendrier de la console.
GET /api/v1/routing/status
Health-check enrichi (jobs actifs, version, uptime). Peut être utilisé pour les systèmes de monitoring ou les readiness probes.
Le champ algorithms_available est réservé aux comptes administratifs ; pour les autres, c'est toujours un tableau vide.
POST /api/v1/routing/simulate
Lance une simulation what-if (Control Tower) à partir d'un job baseline. Renvoie un simulation_id ; le résultat est un job d'optimisation marqué 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" }
]
}
Patches pris en charge : add_delivery (aussi retrait avec point_type=pickup et pickup_point_id), remove_delivery, add_driver, remove_driver, delivery_time_window, balance_options, invalidate_matrices. baseline_scope=PLANNED (LIVE non pris en charge en v1).
GET /api/v1/routing/simulations/{simulation_id}
Renvoie les métadonnées et la comparaison de la simulation (baseline vs résultat what-if).
POST /api/v1/routing/estimate-workload
Estime le besoin de travail (minutes/driver) avant de choisir la flotte. mode=quick (heuristique rapide) ou precise (solveur avec flotte virtuelle).
GET /api/v1/routing/delivery-execution/summary
KPI d'exécution des livraisons (ex. ponctualité %) agrégé sur les derniers jobs de l'utilisateur.
GET /api/v1/routing/jobs/{job_id}/delivery-execution
Détail d'exécution des livraisons et preuves de livraison (POD) pour un job unique.
POST /api/v1/routing/manual-assignments
Permet de fixer livraisons → driver avant de lancer l'optimisation. Les autres endpoints GET/DELETE /manual-assignments permettent la lecture/réinitialisation des préférences.
POST /api/v1/routing/jobs/{job_id}/generate-real-map
Crée des cartes HTML persistantes (dossier web/static/maps) prêtes à être distribuées aux drivers. GET .../download-map et GET .../export génèrent respectivement les cartes et Excel.
POST /api/v1/routing/jobs/{job_id}/generate-geometries
Génère les géométries routières pour un job terminé (JWT obligatoire). En-tête optionnel If-Match avec routes_version_hash ; mismatch → 409 routes_version_mismatch — réessayer sans en-tête (les géométries proviennent du job enregistré).
GET /api/v1/routing/driver-maps
Liste des cartes driver du tenant courant (JWT obligatoire ; 401 sans jeton). Un superuser sans impersonation peut voir tous les tenants.
Geocoding (authentifié)
JWT obligatoire. POST /optimize ne géocode pas : lat/lng numériques dans le JSON restent obligatoires. Appelez d’abord ces endpoints. source est une étiquette de diagnostic, pas un contrat.
POST /api/v1/geocoding/lookup
Cache uniquement, 500 adresses maximum. hit false = absent du cache (utilisez forward). Ne lance pas de résolution externe.
{
"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
Résout jusqu’à 10 adresses (raw + query). origin : api (défaut), wizard, mobile, one_driver, simulator, rubrica. Budget d’environ 25 secondes. status : ok, not_found, pending (répétez le même appel), 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=
Une seule adresse, même résolveur que forward. 200 avec lat/lng ; 400 si address manque ; 404 sans résultat ; 503 si la résolution est encore pending.
GET /api/reverse_geocode?lat=&lng=
Coordonnées vers adresse. 200 { address, source } ; 400 si lat ou lng manque ; 404 sans résultat.
Pins coordonnées Enterprise
Plan Enterprise : stocker adresses et coordonnées. Les pins du tenant priment sur lookup/forward. Capture optionnelle depuis POST /optimize.
POST /api/v1/geocoding/pins
Upsert jusqu’à 500 pins. Même rôle que DELETE et PUT settings : owner, admin ou superuser, plus la feature geocode_pins. Un member reçoit 403 owner_or_admin_required. Chaque élément de results a index, status, pin_id, address_key, error.
status : created (nouveau), updated (même adresse, coordonnées déplacées d’au moins 5 m), unchanged (déplacement sous 5 m), rejected (error : invalid_address, invalid_coordinates, zero_coordinates, swapped_lat_lng, out_of_area), limit_reached (plafond de pins du tenant). summary reprend les mêmes compteurs.
address_key utilise la même normalisation que lookup et forward : Unicode NFKC, minuscules, espaces compressés, virgules rendues « , », espaces et virgules de bord retirés, 500 caractères max. La même chaîne en POST et en lookup trouve le pin : utilisez la valeur renvoyée. Le numéro, le code postal ou des mots en plus changent la clé ; pas la casse ni les espaces doubles.
{
"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
Liste des pins pour qui a la feature (q à partir de 3 caractères, external_id, limit, after_id).
DELETE /api/v1/geocoding/pins/{pin_id}
Supprime un pin du tenant. Owner, admin ou superuser uniquement. Le pin d’un autre tenant renvoie 404.
GET / PUT /api/v1/geocoding/pins/settings
GET (feature) : enabled, auto_capture, count, max_pins. PUT (owner/admin) : corps obligatoire { "auto_capture": true|false }. Réponse PUT : enabled, auto_capture, max_pins.
{ "auto_capture": true }
Export Excel (authentifiés)
POST /api/v1/routing/export-geocoded-deliveries
Nécessite Authorization Bearer. Renvoie un fichier Excel à partir du payload envoyé.
POST /api/v1/routing/export-geocoded-drivers
Nécessite Authorization Bearer. Renvoie un fichier Excel à partir du payload envoyé.
POST /api/v1/routing/export-manual-drivers
Nécessite Authorization Bearer. Renvoie un fichier Excel à partir du payload envoyé.
POST /api/v1/routing/export-manual-deliveries
Nécessite Authorization Bearer. Renvoie un fichier Excel à partir du payload envoyé.
POST /api/v1/routing/export-manual-pickups
Nécessite Authorization Bearer. Renvoie un fichier Excel à partir du payload envoyé.
Endpoints publics / bootstrap
GET /api/v1/public/features
Renvoie les flags frontend : gel_proximity_enabled, rlp_bryntum_timeline_enabled et bootstrap PostHog (posthog_enabled, posthog_host, posthog_project_api_key, posthog_session_replay, posthog_unmask_replay). Bearer optionnel : sans jeton GEL est false ; avec jeton, le tenant et le tier sont évalués. Si PostHog est désactivé ou incomplet, posthog_enabled est false et la project key n'est pas exposée.
GET /api/v1/public/fuel-prices
Moyennes carburant et énergie, sans authentification. Ce n'est pas un historique iCarry : snapshot courant de MIMIT (moyennes journalières Italie et par région) plus GNL/HVO des stations et recharge publique AC/DC mensuelle. Pour l'UI et les estimations de coût, pas pour la facturation et sans SLA sur les sources tierces. Ce n'est pas le champ prezzo_litro de la tournée.
Cache-Control public, max-age=1800 : respecter ce TTL en polling. national et regions : gasolio, benzina et GPL en €/L, méthane en €/kg (regions[].name est le nom de région MIMIT, ex. Lombardia). extended.gnl (eur_kg), hvo (eur_l), electric_ac/electric_dc (eur_kwh) avec value, unit, updated, source. Si toutes les sources échouent : {"available": false}. Le PUN GME n'est pas inclus. L'exemple JSON est structurel, pas des valeurs live.
{
"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" }
}
}
L'endpoint pour la liste des points de retrait GEL sur la carte n'est pas inclus dans cette documentation partenaire publique. Il est décrit dans la documentation interne (superadmin) et fourni sur demande si prévu par le contrat. Contactez le support pour les intégrations locker.
Dictionnaire des données d'entrée (Excel/CSV ↔ JSON)
Les colonnes officielles des modèles correspondent aux champs de POST /api/v1/routing/optimize. Téléchargez les modèles vides, puis envoyez du JSON géocodé. L'ordre des colonnes est défini dans les modèles livraisons et drivers.
Modèles : GET /api/v1/templates/delivery-template et GET /api/v1/templates/driver-template (XLSX/CSV). Il n'existe pas de téléchargement pickup séparé : utilisez la feuille livraisons avec point_type=pickup.
En Excel, lat/lng peuvent manquer si l'adresse est géocodable. POST /optimize exige toujours des lat/lng numériques (et start_lat/start_lng pour les drivers).
POST /api/v1/files/upload est uniquement du stockage : il ne parse pas les colonnes ni ne lance l'optimisation. L'intégration API partenaire est du JSON vers /optimize.
Livraisons / arrêts (delivery_points[])
| Excel | JSON /optimize | Oblig. | Type | Usage |
|---|---|---|---|---|
tracking_number | tracking_number | oui | chaîne ≤64 | ID d'arrêt |
delivery_address | address | oui (ou lat+lng) | chaîne | Géocodage / affichage |
delivery_company | delivery_company | oui en JSON (défaut import « Cliente ») | chaîne | Métadonnée |
lat / lng | lat / lng | oui en JSON ; fac. en Excel s'il y a une adresse | degrés | Matrice / géométrie |
tot_items | tot_items | non (défaut 1) | int ≥1 | Capacité (colis) |
priority | priority | non (défaut 1) | 1–10 (1 = haute) | Priorité / drop |
estimated_duration | estimated_duration | non | minutes | Temps d'arrêt |
notes | notes | non | chaîne ≤500 | App driver uniquement |
phone | phone | non | E.164 (+ et chiffres, ex. +393331234567) | Téléphone destinataire (lien tel dans l'app et Control Tower) |
preassigned_driver | preassigned_driver | non | drivers[].name | Lock → mandatory_assignments |
point_type | point_type | non (défaut delivery) | pickup | delivery | Ordre retrait→livraison ; pickup sans lien = retrait autonome |
pickup_point_id | pickup_point_id | non | chaîne | Lien retrait→livraison ; absent = retrait autonome (retour à la base) |
time_window_start / end | identique | non | HH:MM | Fenêtres horaires |
volume_m3 / weight_kg | identique | non | float ≥0 | Cap volume (poids → 0,001 m³ si volume manquant) |
JSON uniquement (point) : id optionnel (sinon tracking_number ou UUID généré).
Un point_type=pickup sans livraison liée n'est pas écarté : c'est un arrêt obligatoire et la marchandise rentre au point d'arrivée du livreur. En réponse, le point a pickup_mode=return_to_depot et une ligne apparaît dans warnings. S'il n'est pas planifiable, il finit dans unassigned_deliveries.
Drivers / véhicules (drivers[])
| Excel | JSON /optimize | Oblig. | Notes |
|---|---|---|---|
name | name | oui | Identité |
phone | phone | non | Téléphone livreur optionnel en E.164 |
start_address / end_address | — | start obligatoire à l'import | Géocodage → start_* / end_* |
lat / lng | start_lat / start_lng | oui en JSON | Dépôt de départ |
end_lat / end_lng | end_lat / end_lng | oui en JSON (défaut = start) | Retour |
capacity | capacity | non (défaut 50) | Max colis (tot_items) |
max_volume_m3 | max_volume_m3 | non | Cap volume |
vehicle_type | vehicle_type | non (défaut car) | Liste complète ci-dessous : 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 | non | 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 | non | Cap km |
hourly_cost, fuel_consumption, prezzo_litro, costo_pedaggio_km | identique | non | Coûts / rapport |
start_time / end_time | identique | non (08:00–18:00 si paire) | Vacation |
break_start / break_end | identique | par paire | Pause |
max_minutes | max_minutes | non | Durée max (dérivable de vacation−pause) |
JSON uniquement (driver) : id optionnel, active (défaut true), max_overtime_minutes (défaut 0).
Types de véhicule autorisés (liste complète)
On envoie un slug, pas le modèle commercial. Défaut vehicle_type=car. Le 4x4 ou l'aménagement n'ont pas de slug dédié.
| Slug API | Catégorie | Quand l'utiliser |
|---|---|---|
car | Voiture (M1) | Voiture standard. |
van Alias | Fourgons (N1) | Même effet que van_standard. |
van_standard | Fourgons (N1) | Fourgon compact jusqu'à 2,5 t, hauteur environ 1,9 m. |
van_maxi | Fourgons (N1) | Fourgon toit haut jusqu'à 3,5 t, hauteur environ 2,7 m. |
truck Alias | Camions | Même effet que truck_7_5t. |
truck_7_5t | Camions | Camion léger urbain, PTAC 7,5 t. |
truck_12t | Camions | Camion moyen, PTAC 12 t. Exemple : Iveco TGM 13.250 4x4 → truck_12t. |
truck_18t | Camions | Camion lourd 2 essieux, PTAC 18 t. |
truck_32t | Camions | Camion 4 essieux, PTAC 32 t. |
artic_44t | Semi-remorques | Semi-remorque 44 t, environ 16,5 m. |
bike Alias | Cyclo-logistique | Même effet que icarry_cargo_bike. |
scooter Alias | Voiture (M1) | Même effet que car. |
icarry_cargo_bike | Cyclo-logistique | Cargo bike dernier kilomètre. |
routing_profile, s'il est présent, doit être un slug routier du tableau (pas un alias van/truck/bike/scooter) et a priorité sur vehicle_type.
Alias d'en-têtes fréquents (IT/EN)
L'import de fichier reconnaît aussi des en-têtes alternatifs (normalisés, sans accents). Exemples fréquents :
- Livraisons : 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.
- Driver : 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.
Schéma de données principal
DeliveryPointRequest
Obligatoires en JSON : lat/lng, tracking_number (≤64), address, delivery_company. Optionnels : tot_items (défaut 1), priority (1–10), estimated_duration (minutes), notes, phone (E.164, ex. +393331234567), preassigned_driver, point_type (pickup|delivery), pickup_point_id, time_window_start/end (HH:MM), volume_m3, weight_kg, id.
Correspondance complète Excel↔JSON : voir « Dictionnaire des données d'entrée » ci-dessus.
DriverRequest
Obligatoires en JSON : name, start_lat/lng, end_lat/lng (end par défaut = start). Optionnels : phone (E.164), capacity (défaut 50), max_volume_m3, vehicle_type (défaut car), routing_profile, max_distance_km, coûts, start_time/end_time, break_start/end, max_minutes, active, max_overtime_minutes, id. Excel seulement : start_address/end_address.
vehicle_type — liste complète : car, van, van_standard, van_maxi, truck, truck_7_5t, truck_12t, truck_18t, truck_32t, artic_44t, bike, scooter, icarry_cargo_bike. Défaut car. On n'envoie pas de marque ni de modèle : un Iveco TGM 13.250 4x4 est truck_12t. Alias : van → van_standard, truck → truck_7_5t, bike → icarry_cargo_bike, scooter → car.
routing_profile — override optionnel. Valeurs autorisées : car, van_standard, van_maxi, truck_7_5t, truck_12t, truck_18t, truck_32t, artic_44t, icarry_cargo_bike. S'il est omis, il est dérivé de vehicle_type.
Correspondance complète Excel↔JSON : voir « Dictionnaire des données d'entrée » ci-dessus.
OptimizationParamsRequest
Équilibre distance, temps et charge avec des poids configurables. Les valeurs dépendent des priorités opérationnelles.
RoutingConstraintsRequest
Active les contraintes hard (durée maximale, distance maximale, stops par route). Si non définies, le moteur applique des limites dynamiques basées sur les drivers.
Webhook de fin
Définissez webhook_url dans la requête pour recevoir une POST signée (en-tête X-iCarry-Signature) avec le même payload que RoutingResultResponse. Si le webhook renvoie un code < 300, il est considéré comme livré ; sinon, 3 nouvelles tentatives exponentielles sont effectuées (15 s, 60 s, 180 s).
Temps réel via WebSocket
Connectez-vous à wss://flow.icarry.it/ws/jobs et rejoignez la salle job_{job_id} via l'événement Socket.IO join_room. Vous recevrez les événements job_progress, job_completed, job_failed.
Outils d'assistance
- Modèles CSV/XLSX — GET /api/v1/templates/driver-template et /api/v1/templates/delivery-template. Dictionnaire des colonnes : voir « Dictionnaire des données d'entrée » sur cette page.
- Cartes driver — GET /api/v1/routing/driver-maps liste les cartes du tenant (JWT). Les URL HTML de chaque carte restent des capability links.
- Driver App HTML — GET /api/v1/routing/jobs/{job_id}/download-driver-app?driver_name={driver_name} renvoie la version hors ligne de la carte d'un seul driver.
Erreurs et bonnes pratiques
| Code | Scénario | Comment réagir |
|---|---|---|
| 400 | Erreur de validation (schéma Pydantic) | Lisez detail pour le champ erroné ; appliquez une sanitisation côté appelant. |
| 401 | Jeton manquant ou expiré (aussi driver-maps / export Excel sans Bearer) | Régénérez le jeton et répétez l'appel. |
| 403 | Valeur algorithms non autorisée (utilisez auto ou standard) | Utilisez auto ou standard, ou contactez le support. |
| 403 | Endpoint admin/superuser sans privilèges | Les endpoints tenant-admin nécessitent is_admin ; les mutations facturation/algorithmes et settings nécessitent is_superuser. |
| 409 | Job en double en file d'attente (même session_id) | Utilisez des sessions uniques pour les jobs parallèles. |
| 409 | routes_version_mismatch (If-Match / modification concurrente des itinéraires) | Rechargez le hash du job, ou réessayez generate-geometries sans If-Match. |
| 503 | Dépendance non configurée (ex. jeton webhook GEL absent) | Configurez le jeton/secret requis dans les paramètres admin ou l'env, puis réessayez. |
| 500 | Erreur interne / Service de routage injoignable | Réessayez avec backoff. Vérifiez l'état avec /api/v1/routing/status. |
Pour réduire les temps de réponse, définissez des lots entre 80 et 120 livraisons par job ; au-delà de 150 arrêts, envisagez le fractionnement automatique (flag allow_partial_assignments true) et des recompositions ultérieures.
Support
Pour les fonctionnalités avancées (moteur haute performance, SLA prioritaires, environnements dédiés) ou pour activer le filtrage IP sur les endpoints de production, contactez [email protected] en indiquant votre client_id et l'IP publique à autoriser.
🚀 TMS integration guide (Transport Management System)
This guide summarizes how to integrate iCarryUP routing and optimization APIs with your TMS using server-to-server calls (no web UI). For the full Italian walkthrough with extended code samples, switch locale to Italiano.
Quick index
1. Introduction
Use the versioned API under /api/v1. Typical flow: your TMS sends drivers and stops → iCarryUP runs optimization → you poll GET /routing/jobs/{id} or receive a webhook_url callback → import routes back into the TMS.
- Automation — batch daily or on-demand re-optimization.
- Reliability — async jobs, retries on webhooks, health via
/routing/status.
2. Setup
2.1 Credentials
Request a technical user from [email protected] (roles, IP allowlisting if needed).
2.2 Base URL
| Environment | Base URL | When to use |
|---|---|---|
| Production | https://flow.icarry.it |
Live traffic |
2.3 Connectivity check
curl -s "https://flow.icarry.it/api/v1/routing/status"
Example fields: status, version (e.g. 2.9.23-1), active_jobs, routing_service_status. No auth required for reachability. The field algorithms_available is reserved for administrative accounts; for others it is always [].
2.4 Public API & GEL map layer
Use GET /api/v1/public/features to see whether GEL proximity features apply to your integration (same as the Public endpoints section above). Bearer is optional; with a valid token, tenant map setting and gel_proximity on profile/tier are applied.
On POST /api/v1/routing/optimize, you may set per-stop pickup_point_id and gel_cost_to_time_equivalent_minutes_per_eur in optimization_params. If the token user lacks effective gel_proximity, the API strips these fields silently before solving — validate flags/tier before relying on GEL in optimization.
3. Authentication
OAuth2-style password grant to obtain a JWT, then Authorization: Bearer <token> on API calls.
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"
Refresh before expiry (often ~24h). Prefer dedicated technical users for server-to-server flows.
4. End-to-end workflow
- Map TMS stops/drivers to
RoutingOptimizationRequest(see main schema section on this page). - If lat/lng are missing, resolve addresses with
POST /api/v1/geocoding/forward(orlookupfor cache hits only).POST /optimizestill requires numeric coordinates. See Geocoding. - Optional (Enterprise): sync your pins with
POST /api/v1/geocoding/pinsso later lookups reuse your coordinates. You can also enable auto-capture fromPOST /optimizevia/api/v1/geocoding/pins/settings. POST /api/v1/routing/optimizewithasync_processing: true→ receivejob_id.- Poll
GET /api/v1/routing/jobs/{job_id}every 5–10s or subscribe to websocket / webhook. - When
statusis completed, readresult; export maps or Excel via dedicated endpoints if needed.
5. Minimal optimize example
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"
}'
Why time, distance, balanced, and cost exist: choice guide.
6. Webhooks
Set webhook_url on the optimize request to receive a POST with the same shape as the completed job result. Optional X-iCarry-Signature verification. Failed deliveries retry with backoff.
7. Best practices
- Batch roughly 80–120 stops per job when possible; split very large instances.
- Use unique
session_idvalues to avoid 409 duplicate-job conflicts. - Handle 401 by refreshing tokens; 403 may mean blocked algorithm or missing admin rights.
- Monitor
/routing/statusand job error payloads for integration health.
8. Troubleshooting & support
Include job id, HTTP status, redacted payload, and timestamps when writing to [email protected].