Spedizioni multi-carrier per ecommerce italiano: 3PL, GLS e tracking unificato in un'unica console
- shipping
- ecommerce
- automation
L’ecommerce italiano vive con tre tipologie di intermediari per la logistica: un 3PL che si occupa di magazzino e fulfillment, uno o più corrieri nazionali per la consegna, e un servizio di tracking aggregato per non far impazzire il customer care. Tre fornitori, tre API molto diverse, tre lingue. Ognuno ha le sue eccezioni (giacenze, tentativi falliti, indirizzi sbagliati), i suoi webhook, i suoi formati. Quando il volume cresce, il problema non è “spedire”: è capire dove sono i pacchi e perché alcuni sono fermi.
Questo post racconta come abbiamo unificato in una sola console operativa l’integrazione con un 3PL Italia, il portale corrieri di una delle maggiori reti nazionali (con WebLabeling e perfino SOAP API), e una piattaforma di tracking aggregato. Settore: footwear ecommerce, volumi medio-alti, mercato italiano. I pattern descritti si applicano a qualunque ecommerce italiano che fa fulfillment esterno + corriere + tracking.
I tre attori e perché ognuno serve
- 3PL (es. Elogy): riceve gli ordini dallo store, gestisce picking/packing/spedizione. Espone REST API per il push degli ordini e webhook multi-evento per gli aggiornamenti (
new_lead,shipped,delivered,exception). - Corriere nazionale (es. GLS Italia): consegna fisica del pacco. Espone un portale (WebLabeling) per generazione etichette e gestione spedizioni, più API per polling stati e — quando serve — un’API SOAP per operazioni real-time tipo hold/release di giacenze.
- Tracking aggregator (es. Qapla’): normalizza eventi di N corrieri in un formato unico, fornisce widget cliente, email automatiche, e una API webhook per girare gli eventi al merchant.
Ognuno è bravissimo in una cosa. Nessuno è la fonte di verità completa. Il merchant ha bisogno di una vista unica.
Pattern 1: integrazione 3PL con webhook multi-evento
Il push dell’ordine al 3PL è la parte facile: una funzione che mappa l’ordine Shopify nel formato che il 3PL si aspetta (header order, righe articolo, indirizzo, note, servizio richiesto). Il punto delicato è la gestione degli stati.
Il 3PL espone un webhook unico con un campo event_type. Lo handler:
- Verifica firma webhook (HMAC o token shared secret).
- Persiste evento in tabella
shipping_eventsconprovider,event_type,payload,received_at. - Sviluppa l’evento in uno state machine per spedizione (
pending → labeled → in_transit → delivered → exception → resolved). - Notifica i sistemi a valle (customer care UI, customer email via WhatsApp/email, Shopify fulfillment update).
Il sync status complementa il webhook: ogni 30 minuti chiama l’endpoint di status per gli ordini “in flight” e cattura eventi che il webhook potrebbe aver perso (un classico: webhook firmato male = scartato dal nostro handler = stato non aggiornato finché il poll non riconcilia).
Pattern 2: GLS Italia tra WebLabeling, webhook e SOAP
GLS è un caso di studio a sé. Espone tre superfici molto diverse:
- WebLabeling: API REST moderna per generare etichette, prenotare ritiri, leggere stati.
- Webhook push (GLS Italy): notifiche eventi spedizione, formato strutturato ma non sempre completo sui dettagli giacenza.
- SOAP API: per operazioni avanzate tipo
ReleaseShipmentStock(rilascio giacenza), che la REST non copre.
Le giacenze sono la categoria di evento più costosa per il customer care. Una giacenza non risolta entro 48 ore diventa un reso. La nostra soluzione:
- Poll dedicato delle giacenze: ogni 60 minuti, lo script legge le spedizioni in stato “eccezione” dal webhook e dal poll status, e le mette in una coda
giacenze_open. - UI di risoluzione: l’operatore vede la coda con tutti i dettagli e può agire: contatta cliente, richiede ritiro al pickup point, sblocca dal portale GLS.
- Manual resolution logger: quando l’operatore agisce, l’azione viene loggata. Questo permette dopo 3-6 mesi di vedere quali cause di giacenza sono più frequenti (indirizzo errato, destinatario assente, problema documenti) e correggere a monte.
La parte SOAP è la più “old school”. GLS espone un endpoint WSDL per ReleaseShipmentStock: l’integrazione richiede di parsare XML, gestire envelope SOAP, autenticazione tipica enterprise (utente + password + codice cliente nei header). Il pattern che ha funzionato:
- Un Edge Function dedicata (Deno) che costruisce manualmente il body SOAP e parsa la response XML con un parser robusto.
- Retry con backoff su timeout (l’endpoint è notoriamente lento).
- Mapping dei codici errore SOAP nei nostri stati interni, perché il messaggio testuale GLS è in italiano ma non parser-friendly.
Integrare un’API SOAP nel 2026 può sembrare anacronistico, ma per certi servizi legacy è l’unica opzione. Vale la pena isolarla in una singola funzione, con interfaccia REST-like verso il resto del sistema.
Pattern 3: tracking aggregato e reconciliation degli stale
Il tracking aggregator si occupa di normalizzare eventi cross-corriere. Lo collegamo via webhook: ogni evento di tracking arriva, lo persistiamo, e aggiorniamo lo stato visibile al cliente.
Il problema reale è quando il tracking si “incanta”. Un pacco che da 5 giorni è in in_transit senza nuovi eventi è quasi sempre un problema: dimenticato in un hub, indirizzo errato non ancora segnalato, sciopero locale. Il customer care non può guardare ogni singolo tracking.
Lo script di reconciliation qapla_stale_check gira ogni notte:
- Seleziona tutti i tracking in stato non-terminale (
in_transit,out_for_delivery) senza eventi negli ultimi 24 ore. - Per ognuno, forza un refresh chiamando la API del tracking aggregator (non si limita ad aspettare il webhook).
- Se dopo il refresh lo stato non cambia, alza un alert sulla console di customer care con priorità basata su days_since_last_event.
In una settimana tipo lo script identifica 20-40 tracking stale che senza questo check sarebbero arrivati al customer care solo dopo l’email del cliente.
La console unificata: giacenze + logistica in una vista
Tutti questi flussi finiscono in una UI interna che mostra, per ogni spedizione:
- Stato 3PL (ordine ricevuto, packed, shipped).
- Stato corriere (in transit, in delivery, delivered, giacenza, problema).
- Stato tracking (eventi normalizzati cross-carrier).
- Eventuali azioni pending (giacenza da risolvere, indirizzo da confermare, tentativo successivo programmato).
La UI ha filtri rapidi: “spedizioni in giacenza da > 24h”, “spedizioni stale > 48h”, “esistono in 3PL ma non hanno tracking”. È il single pane of glass che permette al team logistica di lavorare per priorità invece che per ordine cronologico.
Esempio concreto: su un volume di 200-300 spedizioni al giorno, la coda “giacenze open” mostra in genere 15-25 record. Il team risolve l’80% in giornata. Senza la vista aggregata, le stesse giacenze emergevano in modo disordinato dai 3 sistemi separati, e si chiudevano in 2-3 giorni. Il guadagno operativo è il tempo del cliente che riceve il pacco, non il tempo del team che lavora a parità di volume.
Pattern replicabile
Se gestisci ecommerce in Italia con 3PL + corriere + tracking:
- Persisti ogni evento webhook in una tabella generica
shipping_events, prima di sviluppare la logica. Avrai bisogno della storia. - State machine unificata per spedizione, non per fornitore. Mappi tu gli stati dei 3 attori nel tuo modello, non il contrario.
- Webhook + poll sempre insieme. Webhook per latenza, poll per affidabilità.
- Coda dedicata per eccezioni (giacenze, stale tracking). Senza, le eccezioni si nascondono nei volumi.
- Isola le API legacy (SOAP, XML) in funzioni singole con interfaccia REST-like verso il resto del sistema.
- Log delle risoluzioni manuali: dopo 3 mesi avrai dati per ottimizzare a monte.
Il setup per un merchant Italia con 3 fornitori logistici è in genere 3-5 settimane. Il ritorno è in customer care (meno ticket “dov’è il mio ordine?”), in resi evitati (giacenze risolte in tempo), e in capacity del team logistica.