L’ERP affiche « annulation réussie », mais le préparateur vient de coller l’étiquette sur le carton. Le connecteur Sendcloud n’a enregistré aucune exception HTTP ; le dossier est donc sorti de sa file de surveillance. Cette conclusion est trop rapide : la demande peut être acceptée sans que l’étiquette soit déjà annulée, et une annulation signalée par le service d’expédition ne démontre pas l’arrêt du colis dans l’entrepôt. Le risque est de remettre en vente des pièces encore affectées à un colis susceptible de quitter l’entrepôt.
Le diagnostic présenté concerne une intégration existante de l’API Sendcloud V2. Son exemple officiel historique distingue déjà une annulation, une mise en attente et une suppression. Nous reproduisons ici la lecture de ces réponses avec Requests 2.32.5 : treize requêtes préparées par la bibliothèque, treize réponses HTTP fictives et 89 contrôles. Aucun colis, aucune étiquette et aucun stock réel ne sont modifiés.
Le résultat utile est une séparation exploitable par les opérations : réponse HTTP reçue, résultat d’annulation interprété et arrêt de préparation confirmé. Une même réponse peut réussir au premier niveau et laisser les deux autres ouverts. Le programme montre notamment que raise_for_status() ne lève aucune exception pour un HTTP 202 ; cette absence d’erreur ne constitue pas une autorisation de remettre le stock en vente.
Notre prestation d’intégration Sendcloud avec vos logiciels métier permet de reprendre cette correspondance entre transport et entrepôt. L’intégration API de vos flux opérationnels doit garder le colis concerné, la réponse effectivement reçue et le traitement encore attendu. Le sujet est la reprise d’un connecteur V2 déjà utilisé ; il ne recommande pas V2 pour un nouveau projet.
Le colis est encore au poste de préparation
Pour qui ce diagnostic évite une fausse clôture
Le cas intéresse les équipes e-commerce, support et logistique qui annulent une commande alors que son expédition est déjà préparée. La demande peut partir d’un ERP, d’un OMS ou d’une application interne ; Sendcloud porte l’objet d’expédition et le WMS organise le travail physique. Ces responsabilités doivent être rapprochées sans supposer que les logiciels partagent spontanément le même état. Une réponse du transport ne remplace pas une confirmation du poste de préparation.
Dans cet exemple concret, le colis fictif 990000107 est encore au poste de préparation. La commande doit être arrêtée, mais l’étiquette a déjà été imprimée. Le connecteur adresse une demande d’annulation et obtient un HTTP 202. Si son écran transforme « aucun HTTPError » en « colis annulé », le support peut annoncer une fin de traitement que personne n’a vérifiée. Une remise à disposition du stock pourrait alors coexister avec un carton encore destiné au départ.
Retrouver l’identité utilisée au moment de la demande
Commencez par l’identifiant Sendcloud réellement placé dans l’URL, puis retrouvez son association avec la commande, la préparation et l’étiquette. Le numéro de commande affiché au support ne suffit pas à prouver quelle ressource a été visée. Une réimpression ou une nouvelle préparation peut avoir changé les associations internes. Il faut conserver le lien tel qu’il existait lors de l’appel, plutôt que recalculer ce lien à partir du dernier état disponible.
Dans notre exercice, un HTTP 200 portant un résultat d’annulation est volontairement comparé à une autre identité attendue, 990000108. La politique locale retourne wrong_target. Elle ne découvre aucune erreur chez Sendcloud : elle refuse simplement d’affecter le résultat de la requête du premier colis au dossier du second. Les deux identifiants sont fictifs et ne représentent aucune expédition consultée sur la plateforme.
Reconstituer la réponse V2 sans changer sa signification
Trois résultats qui ne doivent pas partager le même libellé
La référence officielle d’annulation V2 distingue le colis annoncé du colis non annoncé. L’annulation conserve un colis annoncé dans le système ; la suppression d’un objet non annoncé est un autre résultat. La documentation indique également qu’une demande peut rester en attente. Il faut donc lire le contrat de cette opération, pas seulement la catégorie générale du code HTTP.
L’exemple Python publié par Sendcloud et archivé en 2024 contient déjà les branches 200, 202 et 410. Il montre un appel V2 avec requests.post et prévient que la réponse dépend de l’état du colis. Cet exemple établit l’ancienneté du problème de lecture ; il ne constitue pas une recommandation de recopier un ancien connecteur en production.
Lire le corps au niveau de l’interface réellement appelée
Pour le succès V2 documenté, le corps porte directement status et message. Dans le témoin ci-dessous, le premier champ vaut cancelled. Nous ne lui ajoutons pas l’enveloppe data utilisée par certaines opérations V3. Le programme inclut justement une réponse fictive sous cette autre enveloppe : elle réussit au niveau HTTP, puis reste non résolue à notre frontière V2.
{
"status": "cancelled",
"message": "Parcel has been cancelled"
}
Le témoin 202 utilise un corps vide, car la référence V2 consultée ne donne pas de schéma JSON pour ce retour. C’est une réponse construite pour le test, sans capture de compte Sendcloud. Notre branche classe la demande en attente à partir du HTTP 202 ; elle n’attend pas un champ status documenté dans un autre contrat.
Ce que Requests fait réellement du HTTP 202
Une bibliothèque HTTP ne connaît pas la préparation du colis
Dans le code de Requests 2.32.5, Response.raise_for_status() déclenche une HTTPError pour les réponses d’erreur concernées. Les deux témoins 200 et 202 ne déclenchent pas cette exception. La propriété Response.ok est également vraie dans les deux cas. La bibliothèque n’a pourtant lu aucune confirmation d’arrêt en entrepôt : elle ne possède pas cette règle métier.
Cette observation vise un défaut de mapping : le connecteur réduit une réponse complexe à un booléen, puis ce booléen devient le statut d’annulation dans l’ERP. Le support ne peut plus distinguer une demande en attente d’un résultat d’annulation. Conserver le code HTTP et le résultat interprété permet de retrouver cette différence, sans attribuer à Requests une décision qu’elle n’a jamais prise.
Garder une troisième sortie quand le succès HTTP est inexploitable
Les réponses fictives comprennent aussi un JSON invalide, un tableau JSON et un objet dépourvu du message attendu. Le client HTTP peut recevoir ces contenus sans lever une HTTPError. Notre interprétation locale refuse néanmoins de clôturer le dossier. Elle retourne unresolved, ce qui signifie que le connecteur ne dispose pas de la preuve qu’il exige ; ce libellé n’est pas un statut natif Sendcloud.
La version Requests 2.32.5, publiée en août 2025, est figée pour rendre le test reproductible. Les modules Python installés ont été comparés au paquet officiel. Ce choix permet de vérifier un comportement précis de la bibliothèque ; il ne décide pas de la version, des dépendances ou de la politique de maintenance à retenir pour votre application actuelle.
Exercice isolé : treize réponses, aucune annulation réelle
Suivre la requête préparée et la réponse synthétique
Le programme Python complet de lecture des annulations construit treize requêtes via une véritable session Requests. Un adaptateur local retourne ensuite les réponses fictives. Il vérifie la méthode POST, le chemin du colis et le corps préparé. Il ne transmet rien à Sendcloud, ne fournit aucune clé API et ne simule pas un serveur capable de valider vos droits ou les règles d’un transporteur.
L’exécution utilise Python 3.14.8 et passe les 89 contrôles ci-dessous. Les commandes d’installation servent à préparer une reproduction séparée ; les compteurs proviennent de notre exécution du fichier téléchargeable. Un garde intercepte les tentatives de connexion par socket. Les treize requêtes sont donc des passages par le client et l’adaptateur de test, et non treize appels réussis à une API distante.
python3 -m venv .venv-sendcloud-cancel
.venv-sendcloud-cancel/bin/python -m pip install requests==2.32.5
.venv-sendcloud-cancel/bin/python sendcloud_cancel_response.py
checks_passed: 89
native_prepared_requests: 13
synthetic_http_responses: 13
real_connection_attempts: 0
real_label_or_stock_writes: 0
Comparer les sorties avant de modifier le connecteur
Le tableau reprend les résultats réellement obtenus avec nos données fictives. La colonne de droite appartient à notre politique de lecture. Elle n’est ni une propriété du SDK Sendcloud, que le programme n’utilise pas, ni une preuve d’état sur un compte réel. La mise en attente reste ouverte même si un corps contradictoire annonce une annulation : ce contre-exemple vérifie que notre branche 202 ne se clôture pas sur ce contenu inattendu.
| Réponse fictive | Sortie observée |
|---|---|
| 200 : cancelled et message | Pas d’HTTPError ; annulation signalée, arrêt WMS non établi. |
| 202 : corps vide | Pas d’HTTPError ; demande en attente. |
| 410 : deleted et message | HTTPError ; suppression distinguée. |
| 404 : corps vide | HTTPError ; résultat non résolu. |
| 200 : JSON invalide ou autre enveloppe | Pas d’HTTPError ; lecture V2 non résolue. |
| 200 : autre colis attendu | Refus local : ce n’est pas le colis attendu. |
Le timeout de cinq secondes passé à Requests est un paramètre du témoin. Aucun délai réseau n’est mesuré par cet adaptateur local ; il ne fournit donc aucune preuve de latence ni aucun engagement de service Sendcloud. De même, le nombre de contrôles décrit les assertions du programme. Il ne mesure ni la couverture complète de l’API, ni les scénarios possibles de tous les transporteurs.
Erreurs fréquentes : ranger le code 410 dans la mauvaise opération
Une suppression reconnue peut rester une erreur pour le client HTTP
Paradoxalement, le témoin de suppression déclenche une HTTPError, tandis que celui de mise en attente n’en déclenche aucune. L’objet réponse reste accessible dans l’exception ; le programme lit ensuite le contenu de suppression prévu par sa règle locale. Une gestion qui relance toute HTTPError sans lire la réponse risque de rejouer une opération dont l’effet doit d’abord être clarifié. L’exemple historique du fournisseur traite d’ailleurs ce code séparément.
La documentation V2 archivée sur l’annulation et la suppression explique la différence entre conserver le colis annoncé après annulation et supprimer un objet non annoncé. Cette distinction concerne l’objet de la plateforme. Elle ne prouve pas où se trouve un carton, si une étiquette imprimée reste au poste ou si un opérateur a déjà remis le colis au transporteur.
Un résultat manquant ne doit pas devenir une confirmation inventée
Un HTTP 404 ne démontre pas à lui seul une suppression antérieure. Le connecteur peut viser une identité différente, un dossier mal associé ou une ressource dont il ne peut pas établir l’état. Notre sortie non résolue garde cette incertitude visible. Elle n’autorise ni une nouvelle expédition automatique, ni une écriture de stock destinée à faire disparaître l’anomalie de l’écran.
Ne fusionnez pas non plus les reprises de cette opération avec celles des méthodes d’expédition ou des points relais. Le diagnostic des références Sendcloud qui changent pendant une migration porte sur le choix de service et sa correspondance. Une méthode corrigée n’établit pas le résultat d’une demande d’annulation déjà envoyée pour un autre objet.
Si le carton a déjà quitté l’entrepôt, il faut aussi distinguer l’annulation demandée d’un éventuel parcours de retour. Le diagnostic DHL : un retour à l’expéditeur apparaît livré au client examine un autre défaut de lecture : la livraison d’un retour affectée à la mauvaise destination métier. Il ne fournit aucune commande de retour Sendcloud. Il aide à séparer l’arrêt avant départ du suivi d’un colis déjà remis au transporteur.
Empêcher le stock de repartir sur un accusé incomplet
Définir ce que l’entrepôt doit confirmer
Le programme laisse la libération de stock bloquée pour les treize réponses tant qu’aucun arrêt entrepôt n’est confirmé. Même le témoin d’annulation 200 n’invente pas cet accusé. Une entrée fictive distincte peut ensuite indiquer que l’arrêt est confirmé ; notre fonction passe alors à ready_for_business_review. Elle ne remet toujours aucune quantité en vente et n’appelle aucun ERP ou WMS.
Dans votre contexte, le responsable logistique doit définir la preuve utilisable : préparation arrêtée dans le WMS, colis sorti de la zone de départ, étiquette écartée ou autre contrôle adapté à votre organisation. Le connecteur doit savoir qui produit cette information et à quelle préparation elle se rattache. Par exemple, si le HTTP 202 est reçu, alors notre politique conserve la mise en attente même après un arrêt WMS confirmé. Le seuil d’admission doit rester explicite : un résultat d’annulation pour le bon colis et la preuve d’arrêt convenue, plutôt qu’un simple code de la famille 2xx.
Conserver les décisions séparées pendant les reprises
Une queue ne doit pas effacer le 202 au seul motif que le worker a terminé sans exception. La sortie du worker indique que la demande est rangée en attente, pas que le colis est annulé. Sa prochaine action dépend du contrat de suivi retenu avec Sendcloud et de la preuve attendue ; le programme ne réalise aucun polling distant. Le dossier d’annulation doit rester consultable tant que le résultat n’est pas établi ou que l’écart n’est pas repris par une personne responsable.
L’idempotence concerne ici l’opération métier et le colis visé, pas seulement l’identifiant du message technique. Relancer le même dossier sous un nouvel identifiant sans retrouver son premier résultat peut brouiller les associations et les preuves. Conservez la demande initiale, les observations suivantes et les décisions de reprise. Cette recommandation ne suppose aucun en-tête d’idempotence natif Sendcloud : le témoin n’en prépare pas et ne démontre pas sa prise en charge.
Plan d’action : reprendre le dossier par son colis
Corriger le premier statut trompeur avant de rejouer
Choisissez un dossier qui affiche une annulation réussie alors que son état opérationnel reste douteux. L’équipe du connecteur retrouve l’appel et son résultat brut ; le support vérifie le message présenté au client ; l’entrepôt confirme le sort de la préparation. L’intégration des annulations Sendcloud dans votre SI doit relier ces réponses. Il faut aussi définir avec l’intégrateur ERP qui possède la décision de disponibilité, au lieu de l’inférer du transport.
- Retrouver le colis placé dans l’URL et son association à la préparation concernée.
- Conserver le code HTTP et le corps reçu avant toute traduction en statut métier.
- Séparer mise en attente, annulation signalée, suppression et résultat non résolu.
- Obtenir la preuve d’arrêt entrepôt convenue avant d’examiner une remise à disposition.
- Rejouer un dossier qualifié et vérifier chaque affichage avant d’élargir la correction.
Le monitoring doit distinguer les demandes en attente des annulations signalées. L’observabilité relie ces états au colis, à la commande et à l’arrêt attendu dans le WMS. Une durée de traitement du worker ne mesure pas le délai d’arrêt du colis. Pour définir un SLA, l’équipe choisit le point de départ et la preuve finale qu’elle maîtrise ; aucun délai contractuel ne découle de nos réponses synthétiques.
Prévoir une issue quand les logiciels ne permettent plus de conclure
Le runbook décrit séparément un timeout sans réponse, un 202 reçu et une erreur de lecture du corps. Un retry aveugle n’a pas la même justification dans ces trois cas. La journalisation doit conserver le résultat initial et l’action de reprise autorisée pour cette demande. Il doit également prévoir le dossier où la demande est reconnue côté plateforme, mais où la préparation continue. Le support a alors besoin d’un responsable et d’une action opérationnelle, pas d’un statut « vert » destiné à masquer le désaccord.
Avant la mise en production, comparez aussi les écrans et les notifications qui consomment ce statut : historique ERP, suivi OMS, poste WMS et message client. Un mapping corrigé dans un seul écran laisse les autres acteurs travailler sur l’ancienne conclusion. Gardez la version de la règle et un périmètre de retour arrière. Revenir à l’ancien code n’annule toutefois aucune décision de stock déjà exécutée ; ce traitement demande sa propre reprise métier.
Conclusion : rendre l’arrêt explicable jusqu’à l’entrepôt
Le défaut reproduit vient d’une clôture prématurée : Requests accepte le HTTP 202 sans HTTPError, puis le connecteur transforme cette lecture technique en annulation terminée. Les treize réponses fictives rendent la confusion visible. Elles montrent aussi qu’un 410 traité comme une erreur HTTP peut appartenir à une suppression, tandis qu’un 200 peut rester inexploitable pour votre règle de lecture.
La correction consiste à conserver l’identité visée, le résultat d’annulation interprété et l’arrêt de préparation comme des informations distinctes. Aucune ne doit être reconstruite à partir d’un simple booléen de succès. Les 89 contrôles vérifient notre programme isolé ; la confirmation du résultat sur votre compte, avec votre transporteur et votre entrepôt, reste une étape de recette spécifique.
Notre prestation d’intégration Sendcloud peut cadrer ces associations et ces preuves avec vos responsables logistiques et votre intégrateur ERP. Le périmètre couvre la lecture des réponses, la reprise des dossiers et la restitution des états utiles au support, en tenant compte de la migration de votre intégration existante.
Les équipes Dawap peuvent cadrer avec vous la correction du statut ERP qui annonce « annulé » sur une mise en attente, puis relier ce dossier au colis visé et à l’arrêt de préparation encore à confirmer. Cette correction peut s’inscrire dans une intégration API adaptée à vos annulations et à vos décisions de stock.