CarrierAPI — Plateforme d'expédition multi-transporteurs auto-hébergée

Une seule API REST pour les étiquettes d'expédition, les tarifs, le suivi et l'expédition par lots chez plusieurs transporteurs — auto-hébergée, comme alternative à un outil SaaS tel que SendCloud, avec un contrôle total sur ses propres contrats transporteurs.

Expédition multi-transporteurs
FastAPI / Python
Sync NetSuite & Shopify
Auto-hébergé

Rôle & périmètre

Une entreprise d'e-commerce disposant de son propre ERP (NetSuite) expédiait via un outil SaaS, avec les coûts et le contrôle limité sur les contrats transporteurs que cela implique. CarrierAPI en est le remplaçant auto-hébergé : une API qui crée les étiquettes, compare les tarifs, suit les envois et traite les lots chez plusieurs transporteurs, avec les mêmes points de connexion que l'outil précédent pour que la bascule depuis NetSuite soit un remplacement direct plutôt qu'une reconstruction.

  • Une architecture d'adaptateurs par transporteur (PostNL, DHL Express et UPS comme socle ; DHL Parcel, FedEx, GLS et SendCloud lui-même en adaptateurs supplémentaires), si bien qu'ajouter un transporteur n'impose aucune modification du reste du système.
  • Remplacement direct de l'outil SaaS précédent dans NetSuite : mêmes noms de champs personnalisés, modifications minimes de l'intégration SuiteScript existante.
  • Un branchement direct sur les enregistrements Item Fulfillment de NetSuite, plus la synchronisation avec Shopify et une intégration Amazon à côté des transporteurs.
  • Deux façons de gérer les identifiants transporteurs : via l'interface (stockage en base, solution privilégiée) ou via des variables d'environnement (chemin hérité pour les déploiements existants).

Impact

  • Les frais d'expédition et les contrats transporteurs repris en main, au lieu de dépendre des tarifs et conditions d'une couche SaaS intermédiaire.
  • Reconnaissance d'adresse corrigée pour une catégorie d'adresses jusque-là mal analysées (l'extraction du numéro prenait par erreur le dernier nombre au lieu du premier après le nom de rue — faux par exemple pour les adresses de parcs de vacances comportant à la fois un numéro et un numéro de chalet).
  • Le rapprochement des factures UPS a continué de fonctionner après deux changements du format d'export de leurs factures, grâce à une détection des colonnes basée sur le contenu plutôt que sur des positions fixes, contrôlée face au montant total que la facture annonce elle-même.
  • Colmatage d'une fuite de session où des utilisateurs supprimés conservaient un accès jusqu'à 24 heures, parce que seules la signature et l'expiration de leur jeton étaient vérifiées — pas l'existence du compte.

Architecture

Chaque transporteur est un adaptateur derrière une interface commune (création et annulation d'envois, demande de tarifs, suivi, services disponibles) — brancher un nouveau transporteur ne touche pas au reste du système. Le backend est FastAPI (Python, async) avec PostgreSQL comme base principale et un worker d'arrière-plan basé sur Redis (arq) pour le traitement par lots des étiquettes, si bien que créer des centaines d'étiquettes d'un coup ne bloque pas l'API. Les étiquettes elles-mêmes sont stockées dans MinIO (compatible S3), pour que le stockage ne soit pas lié à un seul fournisseur cloud. Le frontend est un tableau de bord Next.js/React pour gérer les envois, les réglages transporteurs et les identifiants. L'ensemble tourne en auto-hébergement via Docker Compose derrière Traefik, déployé avec Coolify.

Choix du modèle

Pas d'IA/LLM — c'est délibérément un système déterministe : les étiquettes, les tarifs et le suivi doivent être prévisibles et vérifiables, pas générés. Le choix décisif ici était auto-hébergé versus SaaS : un outil SaaS se met en place plus vite, mais une plateforme auto-hébergée donne le contrôle sur les contrats transporteurs, supprime toute redevance par étiquette ou par envoi versée à un intermédiaire, et permet de construire les fonctionnalités (comme l'intégration NetSuite directe) exactement sur mesure au lieu d'attendre ce qu'un éditeur SaaS prend en charge ou non.

Coûts & latence

  • Infrastructure auto-hébergée (Docker Compose, PostgreSQL, Redis, MinIO) au lieu d'une redevance SaaS récurrente par envoi.
  • La génération d'étiquettes par lots tourne en asynchrone via une file Redis (arq), si bien que créer des centaines d'étiquettes d'un coup garde l'API réactive au lieu de faire attendre le demandeur.
  • Rapprochement de factures vérifié sur de vraies factures UPS : notamment une facture de 1 275 lignes à 4 855,72 € et un export de 2 275 lignes, tous deux traités correctement après le correctif sur la détection des colonnes.

Enseignements

L'analyse des adresses néerlandaises échouait sur une catégorie précise (parcs de vacances comportant un numéro de rue et un numéro de chalet distinct, par exemple « Hessenweg 83 41 ») parce que le parseur lisait le dernier nombre de la ligne d'adresse comme numéro de rue au lieu du premier après le nom de rue. Résolu par un parseur commun, vérifié sur un cas réel. L'import des factures UPS a cassé deux fois parce qu'UPS a modifié le format d'export de ses factures (nombre et ordre des colonnes décalés) ; l'approche par positions fixes a été remplacée par une détection des colonnes basée sur le contenu, dont le résultat est recoupé avec le montant total annoncé par la facture. Les avertissements de validation d'adresse bloquaient au départ entièrement la création d'un envoi ; ce comportement a été ramené au seul blocage de l'achat automatique d'étiquette, si bien qu'un envoi signalé reste visible et réessayable au lieu d'être bloqué. Et une vulnérabilité de session : les utilisateurs supprimés gardaient un accès jusqu'à 24 heures parce que les jetons n'étaient vérifiés que sur la signature et l'expiration, pas sur l'existence du compte — corrigé en vérifiant à chaque requête que le compte existe encore.