Documentation publique / partenaires Cette version est destinée aux clients et partenaires qui intègrent les API. Certaines sections réservées aux administrateurs (gestion des utilisateurs, tiers, détails d'infrastructure) ne sont pas incluses.

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é

  1. Chargez les données logistiques (drivers + livraisons) au format prévu par RoutingOptimizationRequest.
  2. Envoyez POST /api/v1/routing/optimize avec async_processing=true ; vous recevez un job_id.
  3. Surveillez l'état via GET /api/v1/routing/jobs/{job_id} (polling 5-10 s) ou via WebSocket /ws/jobs.
  4. Lorsque status=completed, lisez result, exportez les fichiers ou générez des cartes avec les endpoints dédiés.
  5. 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_numbertracking_numberouichaîne ≤64ID d'arrêt
delivery_addressaddressoui (ou lat+lng)chaîneGéocodage / affichage
delivery_companydelivery_companyoui en JSON (défaut import « Cliente »)chaîneMétadonnée
lat / lnglat / lngoui en JSON ; fac. en Excel s'il y a une adressedegrésMatrice / géométrie
tot_itemstot_itemsnon (défaut 1)int ≥1Capacité (colis)
priorityprioritynon (défaut 1)1–10 (1 = haute)Priorité / drop
estimated_durationestimated_durationnonminutesTemps d'arrêt
notesnotesnonchaîne ≤500App driver uniquement
phonephonenonE.164 (+ et chiffres, ex. +393331234567)Téléphone destinataire (lien tel dans l'app et Control Tower)
preassigned_driverpreassigned_drivernondrivers[].nameLock → mandatory_assignments
point_typepoint_typenon (défaut delivery)pickup | deliveryOrdre retrait→livraison ; pickup sans lien = retrait autonome
pickup_point_idpickup_point_idnonchaîneLien retrait→livraison ; absent = retrait autonome (retour à la base)
time_window_start / endidentiquenonHH:MMFenêtres horaires
volume_m3 / weight_kgidentiquenonfloat ≥0Cap 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
namenameouiIdentité
phonephonenonTéléphone livreur optionnel en E.164
start_address / end_address—start obligatoire à l'importGéocodage → start_* / end_*
lat / lngstart_lat / start_lngoui en JSONDépôt de départ
end_lat / end_lngend_lat / end_lngoui en JSON (défaut = start)Retour
capacitycapacitynon (défaut 50)Max colis (tot_items)
max_volume_m3max_volume_m3nonCap volume
vehicle_typevehicle_typenon (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_profilerouting_profilenonOverride : car, van_standard, van_maxi, truck_7_5t, truck_12t, truck_18t, truck_32t, artic_44t, icarry_cargo_bike
max_distance_kmmax_distance_kmnonCap km
hourly_cost, fuel_consumption, prezzo_litro, costo_pedaggio_kmidentiquenonCoûts / rapport
start_time / end_timeidentiquenon (08:00–18:00 si paire)Vacation
break_start / break_endidentiquepar pairePause
max_minutesmax_minutesnonDuré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
carVoiture (M1)Voiture standard.
van AliasFourgons (N1)Même effet que van_standard.
van_standardFourgons (N1)Fourgon compact jusqu'à 2,5 t, hauteur environ 1,9 m.
van_maxiFourgons (N1)Fourgon toit haut jusqu'à 3,5 t, hauteur environ 2,7 m.
truck AliasCamionsMême effet que truck_7_5t.
truck_7_5tCamionsCamion léger urbain, PTAC 7,5 t.
truck_12tCamionsCamion moyen, PTAC 12 t. Exemple : Iveco TGM 13.250 4x4 → truck_12t.
truck_18tCamionsCamion lourd 2 essieux, PTAC 18 t.
truck_32tCamionsCamion 4 essieux, PTAC 32 t.
artic_44tSemi-remorquesSemi-remorque 44 t, environ 16,5 m.
bike AliasCyclo-logistiqueMême effet que icarry_cargo_bike.
scooter AliasVoiture (M1)Même effet que car.
icarry_cargo_bikeCyclo-logistiqueCargo 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 :

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

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.

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.

Partner docs: the GEL pickup-points listing endpoint is not included in this public page. It is documented internally (superadmin) and provided on request when your contract covers lockers. Contact [email protected].

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

  1. Map TMS stops/drivers to RoutingOptimizationRequest (see main schema section on this page).
  2. If lat/lng are missing, resolve addresses with POST /api/v1/geocoding/forward (or lookup for cache hits only). POST /optimize still requires numeric coordinates. See Geocoding.
  3. Optional (Enterprise): sync your pins with POST /api/v1/geocoding/pins so later lookups reuse your coordinates. You can also enable auto-capture from POST /optimize via /api/v1/geocoding/pins/settings.
  4. POST /api/v1/routing/optimize with async_processing: true → receive job_id.
  5. Poll GET /api/v1/routing/jobs/{job_id} every 5–10s or subscribe to websocket / webhook.
  6. When status is completed, read result; 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

8. Troubleshooting & support

Include job id, HTTP status, redacted payload, and timestamps when writing to [email protected].