Journal des modifications de l'API

Historique des versions · Journal des modifications

Journal des modifications de l'API

Aperçu de toutes les modifications et améliorations apportées à l'API REST xoPort.


Versions

v2.122.13 Version actuelle

20 octobre 2026

Corrections de bogues concernant le statut des contrats, la liste des produits par catégorie et le compte de crédit, ainsi que le masque des clients OAuth2 et la remise de fidélité dans l'exportation des commandes openTRANS. Comparaison numérique des numéros de version : la version 2.122.13 succède à la version 2.122.12. À partir de la version 4.9.174 de la boutique.

Contrats : statut des contrats
  • ⚠️ Modification : le point de terminaison de statut PUT /Import/JSON/contracts/{id}/status, l’objet status et le champ contracts_status_id dans l’importation des contrats vérifient l’ID par rapport aux statuts des contrats de la boutique, comme dans le backend. Jusqu’à la version v2.122.12, le point de terminaison de statut et l’objet effectuaient une vérification par rapport aux statuts de commande, et contracts_status_id était écrit sans vérification. Tout statut de contrat de la boutique est valide, y compris un statut désactivé. Récupérez les ID à partir de contracts_statuses[], de GET /Export/JSON/contracts ou de error.valid_status_ids, jamais à partir de /order_statuses.
  • L'ID est lu de manière stricte : un nombre entier ou une chaîne de caractères composée de chiffres ; les espaces en bordure ne sont pas pris en compte. true, [65], "1e3" ou 54.9 ne sont pas des ID : au niveau du point de terminaison de statut HTTP 400 INVALID_STATUS, dans l'importation de contrats, l'avertissement CONTRACT_STATUS_UNKNOWN. Jusqu'à présent, cela a donné respectivement 1, 1, 1 000 et 54.
Casjusqu’à la version v2.122.12à partir de la v2.122.13
Statut de contrat qui n'existe pas également en tant que statut de commande, au point de terminaison de statutHTTP 400 INVALID_STATUSenregistré
… dans l’objet « status » de l’importation de contratsignoré sans autreécrit
⚠️ ID n'existant qu'en tant que statut de commande, enregistré au niveau du point de terminaison de statuten tant que statut de contrat, new_status_name avec le nom du statut de commandeHTTP 400 INVALID_STATUS
⚠️ … dans l’objet status de l’importation de contratsenregistré comme statut de contratStatut inchangé, avertissement CONTRACT_STATUS_UNKNOWN
ID inconnu dans l’objet status ou status sans status_ida été ignoré sans autre, l’enregistrement a été considéré comme créé ou modifiéStatut inchangé, avertissement CONTRACT_STATUS_UNKNOWN
⚠️ contracts_status_id sans statut de contrat valide (ID de statut de commande uniquement, 0, "abc", true)Écrit sans vérification ("abc" = 0, true = 1)non écrit, les autres champs le sont, avertissement CONTRACT_STATUS_UNKNOWN
  • INVALID_STATUS indique les ID valides dans le message et dans error.valid_status_ids. L'avertissement CONTRACT_STATUS_UNKNOWN figure dans warnings[] et dans l'entrée de l'enregistrement dans records[], avec contracts_id et field (status.status_id, status ou contracts_status_id). L'enregistrement continue d'être considéré comme créé ou modifié, seul le statut n'est pas enregistré.
  • new_status_name La réponse du point de terminaison de statut contient désormais le nom du statut du contrat.
  • Un « contracts_status_id » valide est enregistré comme auparavant, sans inscription dans l’historique des statuts. Pour enregistrer un changement de statut avec historique, utilisez l’objet status et le point de terminaison de statut.
  • ⚠️ Les interfaces qui envoyaient jusqu’à présent un ID de statut de commande comme statut de contrat reçoivent désormais un code HTTP 400 ou l’avertissement (lignes marquées d’un ⚠️). Pour en savoir plus : Contracts.
Liste des produits par catégorie
  • ⚠️ Modification : /categories/{id}/productlist renvoie exactement cette catégorie, /categories/{a}:{b}/productlist les catégories a à b et /categories/{a}:/productlist les catégories à partir de a. Jusqu’à la version v2.122.12, la liste des produits de toutes les catégories était renvoyée avec un code HTTP 200 ; pour {id}, un avertissement « RANGE_START_NOT_SINGLE_RECORD » s’affichait ; cet avertissement n’apparaît plus ici.
  • ⚠️ L'ajout de « ?categories_id= » à l'ID ou à la plage dans le chemin d'accès génère une erreur HTTP 400 : FILTER_NOT_APPLICABLE. Seule la même valeur que l'ID du chemin d'accès unique est autorisée. Un ?categories_id= vide ou composé uniquement d'espaces est considéré comme non envoyé.
Requêtejusqu'à la version v2.122.12à partir de la v2.122.13
/categories/5/productlistHTTP 200, toutes catégories, avertissement RANGE_START_NOT_SINGLE_RECORDCatégorie 5
/categories/5:10/productlistHTTP 200, toutes les catégoriesCatégories 5 à 10
/categories/5/productlist?categories_id=5Catégorie 5inchangé Catégorie 5
⚠️ /categories/5/productlist?categories_id=7HTTP 200, catégorie 7HTTP 400 FILTER_NOT_APPLICABLE
⚠️ /categories/5:10/productlist?categories_id=5HTTP 200, catégorie 5HTTP 400 FILTER_NOT_APPLICABLE
/categories/productlist?categories_id=5Catégorie 5inchangé
  • ⚠️ Les requêtes comportant un ID ou une plage dans le chemin d’accès et un ?categories_id= différent recevaient, jusqu’à la version v2.122.12, la catégorie du paramètre ; elles reçoivent désormais un code HTTP 400 (lignes marquées d’un ⚠️). Veuillez envoyer la catégorie soit dans le chemin d’accès, soit en tant que paramètre.
  • En l’absence d’ ?language=, le nom de la catégorie s’affiche dans la langue dont l’ languages_id est la plus faible (dans les boutiques XONIC, 1 = anglais), et non dans la langue par défaut de la boutique. Jusqu’à présent, l’ordre des lignes dans la table des langues était déterminant, mais celui-ci pouvait varier, par exemple après la suppression et la recréation d’une langue. Envoyez un e-mail à ?language= si la langue a son importance. Pour en savoir plus : Catégories.
Compte de crédit : filtre par source
  • ⚠️ Modification : GET /Export/JSON/wallet_logs?source= uniquement avec un espace (?source=%20) signifie « non défini », comme indiqué à l'adresse /orders?source=. Jusqu'à la version v2.122.12, le point de terminaison filtrait alors sur une source vide et renvoyait généralement une liste vide.
Requêtejusqu’à la v2.122.12à partir de la v2.122.13
/wallet_logs?source=%20Filtrage sur une source vide, généralement une liste videcomme s’il n’y en avait pas source
/wallet_logs?source=0Le filtre est ignoré, comme s’il n’y en avait pas sourceuniquement les entrées dont la source est 0 (généralement une liste vide)
  • Inchangé : ?source= avec une autre valeur ; les espaces à la fin de la valeur n’étaient déjà pas pris en compte auparavant.
Backend : clients OAuth2
  • Aucune modification de l’API. À partir de la version 4.9.174 de la boutique, la fonction « Modifier le client » affiche à l’administrateur, pour un client illimité, un champ vide avec la mention « Illimité (défini par XONIC) », et le client reste enregistré comme illimité. ⚠️ Jusqu’à la version Shop 4.9.173, la valeur affichée était 5 000, et chaque enregistrement effectué par l’administrateur écrivait 5 000, même si seuls le nom ou la note avaient été modifiés. À lire également : Clients OAuth2, section « Limite de requêtes ».
  • Si l’administrateur XONIC crée un client avec un champ vide, celui-ci est désormais toujours illimité ; jusqu’à la version 4.9.173 de Shop, il se voyait attribuer la valeur 5 000 en fonction du schéma de la base de données.
  • Lors de la création d’un client, le nom et la note sont enregistrés sans barre oblique inversée supplémentaire (O'Reilly au lieu de O\'Reilly).
Interface XML : remise de fidélité dans openTRANS
  • ⚠️ Modification : l’exportation de commande avec le modèle openTRANS (/Export/XML/order/{id}/opentrans) affiche la remise de fidélité (ot_loyalty_discount) sous forme de réduction, en tant que ligne comme les autres lignes de total, et l’inclut dans TOTAL_ITEM_NUM. Jusqu’à la version v2.122.12, le modèle demandait ot_loyality_discount (faute de frappe) : la déduction manquait, et les lignes étaient supérieures d’autant à TOTAL_AMOUNT.
  • Inchangés : le calcul des lignes de total, l’exportation JSON et les autres modèles XML. Les variantes personnalisées du modèle qui ont repris la liste des lignes de total depuis orders-opentrans.xsl conservent la faute de frappe.

v2.122.12

19 octobre 2026

Correction d'erreur : les paramètres de requête et les segments de chemin d'accès s'appliquent tels que la boutique les vérifie. Comparaison numérique des numéros de version : la version 2.122.12 succède à la version 2.122.11. À partir de la version 4.9.173 de la boutique.

Espace en fin de chaîne : la valeur vérifiée est prise en compte
  • Modification : la validation des valeurs (depuis la v2.122.10) évalue chaque valeur sans espace en bordure : espace (également + dans l’adresse), tabulation %09, saut de ligne %0A/%0D, %00 et %0B. Jusqu’à la version v2.122.11, de nombreux points de terminaison lisaient ensuite la valeur non tronquée, et une valeur qui passait le test s’y comportait en réalité différemment. Désormais, c’est exactement la valeur vérifiée qui s’applique au niveau du point de terminaison, lors des opérations d’exportation, d’importation et de suppression.
  • Modifications : Une valeur vide ou un espace vide signifie « non défini » pour tout paramètre soumis à une règle fixe (nombre, identifiant, bouton, valeur de sélection, date, heure, langue, nom de fichier, lettres et chiffres), y compris dans les points de terminaison qui, jusqu’à présent, vérifiaient uniquement si le paramètre existait.
Demandejusqu’à la v2.122.11à partir de la v2.122.12
?_strict=%20true lors de l’importationle mode strict est désactivé, l’importation s’effectuait partiellementen mode strict
?_strict=true%0A lors de l'exportation, avec un filtre ou un champ inconnuHTTP 200 avec avertissementHTTP 400 comme avec ?_strict=true
/tickets?type=%20jobles tickets et les tâchesuniquement les tâches
/categories?parent_id=5%00, ainsi que les filtres numériques et de sélection sur les contrats, tickets, projets, tâches, rendez-vous et autres points de terminaisonFiltre suppriméFiltre appliqué
/products?bundles=%201, ainsi que « marketplaces » et bonus_free_featuresBloc manquantBloc présent
/products_options_values?orphaned=%20truetoutes les valeursuniquement les orphelines
/porters?status=%20, /products_options?listing_status=%20filtrées à 0, c'est-à-dire, pour les porteurs, les inactivesnon définies
/porters?status=%001, /products_options_values?option_id=%005 (%00 avant le chiffre)lues comme 0 : les ports inactifs ou les valeurs de l'attribut 0la valeur envoyée
/faqs?language=, de même que /faqcats, /cms, /sliders et /categories?language=%20une liste videtoutes les langues, comme sans language
/medias?entity_type=une liste vide avec une remarqueles images des produits, comme sans entity_type
/products_options?with_values= ou %20HTTP 400non défini
GET /seohistorys?type=%20pEntrées de tous les typesuniquement le type p
DELETE /seohistorys?type=p&base_id=42%00a supprimé toutes les entrées de type puniquement les entrées de l'article 42
DELETE /seohistorys?type=%20p&base_id=42a supprimé les entrées de tous les types associées à l'ID 42uniquement celles de type « p » associées à l'ID 42
⚠️ DELETE /seohistorys?type=%20p sans autre filtre, de même que ?base_id=42%00 ou ?expired=1%00 seulsHTTP 400 MISSING_FILTER, rien n'est supprimésupprime toutes les entrées de type « p » portant l'ID 42 ou toutes celles qui ont expiré
⚠️ DELETE /medias?entity_id=7%00HTTP 400 NO_TARGETS ou uniquement les ID figurant dans le corps du messageainsi que toutes les images de l'article 7
⚠️ DELETE /ticket_department/{id}?reassign_to=%005HTTP 409 DEPARTMENT_IN_USETickets déplacés vers le service 5, service supprimé
  • ⚠️ Une suppression ne supprime jamais plus que ce qu’indiquent les valeurs vérifiées, mais elle supprime toutefois davantage qu’avant la version v2.122.11 : les requêtes qui étaient jusqu’à présent rejetées faute de condition valide sont désormais supprimées (lignes marquées d’un ⚠️).
  • Inchangé : valeurs sans espace à la fin, texte libre (mots-clés, noms, codes), filtres avec vérification de valeur propre (filtres produit, client et bon de réduction ; pour les commandes, date et pays de livraison ; là, la valeur vérifiée s’appliquait déjà) ainsi que la navigation et le tri. Tous les cas : API d’exportation, section « Espace libre en bordure ».
Segment de chemin dans l’export JSON
  • Modifié : le segment suivant le point de terminaison est un nombre entier comportant au maximum 18 chiffres (/product/42), une plage avec des limites entières (/orders/100:200, /orders/100:), new:{datum} vers les clients et les commandes ou la sous-route productlist vers /categories. Tout autre cas génère une erreur HTTP 400 INVALID_RANGE, et le message indique le segment concerné. Jusqu’à la version v2.122.11, un segment invalide renvoyait la liste paginée avec un code HTTP 200.
  • Les espaces vides en bordure du segment ne comptent pas : /product/42%20 correspond à l’article 42. Un segment composé uniquement d’espaces vides renvoie un code HTTP 400.
Requêtejusqu'à la version v2.122.11à partir de la version 2.122.12
/product/42%20, /order/42%0AHTTP 200, la listeEnregistrement 42
/product/42x, /order/42%2B, /product//42, /products/productlistHTTP 200, la listeHTTP 400 INVALID_RANGE
⚠️ /product/42.0, /order/+5, /product/1e3, /products/1.5:3Enregistrement 42, 5 ou 1 000, plage de 1 à 3HTTP 400 INVALID_RANGE
⚠️ /orders/new%3A2026-10-01 (deux-points codé)HTTP 200, la liste complète au lieu du deltaHTTP 400 INVALID_RANGE
⚠️ /contracts/10/20Contrats à partir de 10 sans limite maximaleHTTP 400 ; la plage est /contracts/10:20
/categories/5/Productlist, /product/42/xcatégorie 5 ou article 42HTTP 400 INVALID_RANGE
/orders/ avec 19 chiffres ou plusune limite au-delà de tout identifiant, à partir de 309 chiffres, la liste complèteHTTP 400 INVALID_RANGE
  • ⚠️ Même les interfaces qui recevaient jusqu’à présent l’enregistrement souhaité reçoivent désormais un HTTP 400 (lignes marquées d’un ⚠️) : envoyez l’ID sous forme de nombre entier sans décimales ni signe, ce qui est généralement le cas pour les valeurs issues de tableaux. Envoyez le double-point après « new » sans le coder.
  • /categories/{id}/productlist reste autorisé, mais l'ID n'est pas pris en compte : la réponse contient toutes les catégories (à partir de la v2.122.13, filtre par catégorie, voir cette version). Pour récupérer une catégorie, utilisez /categories/productlist?categories_id={id}.
  • Inchangé : exportation au format XML, CSV et TXT (dans ce cas, un segment sans nombre correspond au nom d’un modèle), importation et suppression. Envoyez également les ID sous forme de nombres entiers lors de la suppression.

v2.122.11

18 octobre 2026

Troisième partie des extensions pour les intégrations avec la gestion des stocks et l’automatisation, notamment lors de la création. Comparaison numérique des numéros de version : la version 2.122.11 succède à la version 2.122.10. À partir de la version 4.9.171 de la boutique.

Commandes
  • Modification : si une interface envoie les prix des lignes avec l’ tax_flag e 1 (brut), la boutique enregistre désormais la ligne au prix net, comme pour une commande provenant de la caisse, y compris les majorations propres aux caractéristiques. Auparavant, le prix brut figurait dans la ligne de commande, et l’éditeur de commande, le PDF de la facture, l’e-mail de commande ainsi que l’ajout ultérieur de lignes de commande appliquaient la taxe une deuxième fois. orders:read fournit donc ces lignes de commande au prix net (products_price, final_price, attributes[].options_values_price; 10,00 à 19 % devient 8.40336134). Les interfaces qui récupèrent ces champs et les comparent aux données envoyées procèdent à la conversion. Les montants totaux de la commande restent inchangés.
  • Dans deux cas, c’est désormais la valeur de la caisse qui s’applique : le supplément lié aux caractéristiques présélectionnées (apply_default_attributes) sur un tel poste est pris en compte dans le calcul de la taxe, et un barème de frais de port en fonction de la valeur des marchandises (compute_shipping) se base sur la valeur nette. Les frais d’expédition et le montant total peuvent ainsi varier ; une commande « expected_total » adaptée à l’ancienne valeur indique alors « TOTAL_DRIFT ». Les commandes existantes ne sont pas converties ; si l’on ajoute quelque chose à une ancienne commande dont les lignes sont enregistrées en brut, la double taxation reste en vigueur.
  • Nouveau : champ de position « service » lors de la création (POST et PUT avec products_mode: "append") : 1 = prestation de service, 0 = marchandise, ainsi que true/false ou "1"/"0". La valeur envoyée prévaut sur les données du produit, par exemple dans le cas d’un poste de prestation de service libre sans products_id pour un client professionnel situé dans un autre pays de l’UE. Sans ce champ, la règle du produit s'applique comme auparavant : un poste libre correspond à une marchandise. Une autre valeur génère l'avertissement « service_invalid » dans records[].warnings. Jusqu'à présent, le champ était ignoré ( UNKNOWN_FIELD ).
  • Modification : « products_mode: "update" » rejette « service ». L'enregistrement échoue avec le message « FIELD_NOT_UPDATABLE », rien n'est écrit, pas même dans les autres champs. Jusqu'à présent, un avertissement s'affichait et l'enregistrement était considéré comme « updated ».
  • Modification : la ligne d’expédition d’une commande hors taxes (tax_flag 0) comporte tax 0 et le taux d’imposition dans tax2, comme une commande hors taxes issue de la caisse ; les commandes exonérées d’impôt (tax_flag 2) comportent également 0 et 0 en mode verbatim. Si l’on lit le taux d’expédition uniquement à partir de totals[].tax, on utilise tax2 pour les commandes nettes. Les totaux restent identiques, les commandes enregistrées ne sont pas modifiées. La facture électronique de ces commandes indique désormais le montant correct pour l’expédition.
  • Lors de l’ajout de lignes via PUT, les frais d’expédition d’une commande nette provenant de la caisse sont désormais pris en compte ; auparavant, ils n’apparaissaient pas dans le total général.
Clients : désabonnement à la newsletter
  • Nouveau : customers_nl_lock est accessible en écriture via POST/PUT /customers: 0/1, true/false ou "0"/"1". La valeur exportée peut être renvoyée, notamment via ?_strict=true. Si la valeur est manquante, si elle est « null » ou vide, le blocage reste inchangé. Une valeur invalide génère l'avertissement « INVALID_FIELD_VALUE », le reste de l'enregistrement est enregistré. Jusqu'à présent, le champ était « UNKNOWN_FIELD » (avec « ?_strict=true » et un code HTTP 400).
  • Modification : 1 désabonne tous les abonnements du compte, dans la boutique et auprès du fournisseur de newsletter. Le désabonnement est alors considéré comme une opposition à la publicité et reste valable même après 0; les importations ultérieures rejetteront l’adresse. Une exportation renvoyée avec customers_nl_lock = 1 entraîne également la désinscription ; chez le prestataire, cela ne peut pas être annulé, un abonnement ne peut être réactivé qu’après une nouvelle confirmation. Si le prestataire échoue, la réponse indique NEWSLETTER_UNSUBSCRIBE_FAILED; le blocage est enregistré, l’abonnement est maintenu. 0 ne fait que lever le blocage.
  • ⚠️ Les e-mails publicitaires issus du marketing et des automatisations (xoMarketing) ne sont pas encore bloqués dans Shop 4.9 ; cette fonctionnalité sera disponible à partir de Shop 4.10.
  • Les désabonnements auprès du fournisseur s’effectuent directement dans la requête elle-même, à raison d’un par adresse. Il est donc conseillé de diviser en lots plus petits les grands lots comportant de nombreux comptes bloqués.
  • Dans le CSV-Porter (colonne « customers newsletter lock ») et dans l’importation de clients au format XML (colonne « customers_nl_lock », uniquement avec votre propre XSL, réponse newsletter.locked_removed), la valeur « 1 » est également renseignée. Contrairement à l’API, une cellule vide ou toute autre valeur lève le blocage dans ces cas-là. Le message de refus NEWSLETTER_LOCKED envoyé à POST /newsletter_subscribers (pour les clients utilisant customers:read, sinon NOT_SUBSCRIBABLE) indique désormais la marche à suivre pour lever le verrouillage : PUT /customers avec customers_nl_lock = 0.
Projets
  • Nouveau : relationships[] permet également de lier un projet à des contrats (target_type contracts_id ). Jusqu’à présent, un tel enregistrement échouait (« Invalid relationships »).
  • Modifié : un lien vers une commande, un ticket ou un contrat inexistant n’est plus créé, mais le reste de l’enregistrement est conservé ; warnings[] signale PROJECT_RELATIONSHIP. Si vous renvoyez une exportation via PUT, vous perdez les liens vers les cibles supprimées, car PUT remplace tous les liens.
  • Modification : si relationships n’est pas une liste, l’enregistrement échoue. Jusqu’à présent, POST créait le projet sans liens, et PUT les supprimait tous en silence. L’exportation ne fournit désormais plus que des liens des trois types suivants : orders_id, ticket_id et contracts_id.
Caractéristiques
  • Si POST/PUT /products_options modifie une valeur qui est également liée à une autre caractéristique, un clone avec un nouvel identifiant est créé, comme auparavant. Le clone reprend désormais de l’original les image et sort_id non envoyées ; auparavant, il recevait une image vide et le tri 0. Les valeurs envoyées prévalent. Les clones déjà créés restent tels quels : ajoutez l’image et le tri via PUT.
Produits : lots
  • Nouveau : champ « bundle » sur le produit, contenant les paramètres et les composants d’un lot. L’exportation ne le fournit qu’avec « ?bundles=1 », y compris lors d’une consultation individuelle et dans les sections ; sans lot, la valeur « null » y figure. « ?bundles= » n’accepte que « 0 » ou « 1 », sinon une erreur HTTP 400 est renvoyée.
  • Modification : auparavant, un bundle envoyé en paramètre était ignoré et traité comme UNKNOWN_FIELD. Désormais, c’est le bundle qui le modifie : null le supprime, items[] remplace tous les éléments ; sans la clé, rien ne change. Un bundle non valide entraîne l'échec de l'ensemble de l'enregistrement (INVALID_BUNDLE) ; rien n'est écrit, pas même le prix. bundle_auto_price et bundle_auto_price_percent n'existent pas dans la version 4.9 de la boutique (avertissement BUNDLE_SETTING_UNAVAILABLE).
  • Pour les boutiques provenant d'une version antérieure à la 4.9.155 : après la mise à jour, ouvrez une fois le backend avant que la connexion n'enregistre les bundles.
Produits : places de marché
  • Nouveau : ?marketplaces=1 fournit, pour chaque article, marketplaces[], une entrée par canal de la boutique avec un bouton et un statut : code, status, upload_status, sync_state, last_updated, external_id, messages[] et d’autres. Dans la version 4.9 de la boutique, live correspond toujours à null. Une valeur différente de 0/1 génère une erreur HTTP 400 au lieu de l’avertissement UNKNOWN_FILTER.
  • Nouveau : l'envoi de marketplaces[] à POST/PUT /products active le commutateur pour chaque canal (canal via code ou marketplace_id, status, 0/1) ; les canaux non envoyés restent inchangés. L'écriture ne s'effectue que pour les canaux disposant d'une licence dans la boutique. Jusqu'à présent, la clé était UNKNOWN_FIELD.
  • Le commutateur prend effet lors de la prochaine synchronisation du canal : pour Amazon, eBay, Kaufland et Idealo, 1 crée une offre, tandis que 0 la supprime. Les canaux Mirakl et Shöpping.at ne suppriment pas les offres avec 0; Mirakl ne crée une offre qu’avec des données Mirakl mises à jour ; Check24, Etsy et les canaux sans connexion ne transfèrent rien depuis la boutique (détails sur la page « Products »). Une exportation renvoyée avec marketplaces[] inclut également les commutateurs. Un PUT contenant uniquement l’identifiant de l’article (products_id ou products_model) et marketplaces ne modifie pas la date de modification de l’article ; la ligne de canal modifiée est marquée pour la synchronisation (last_updated 1970-01-01 00:00:00 ).
  • Nouveau : filtre de la place de marché sur /products: ?marketplace= avec ?marketplace_status=, ?marketplace_upload_status= ou ?marketplace_sync_state=, par exemple pour récupérer tous les articles Idealo non à jour en une seule fois. Jusqu’à présent, les noms étaient ignorés ( UNKNOWN_FILTER ) et la liste était renvoyée sans filtrage.
  • Modification (Idealo) : un retrait (status 0 via l’API, le masque d’article, CSV ou XML) est désormais également pris en compte lorsque le stock est nul. Seule une offre que la boutique a elle-même désactivée en raison d’un stock égal à 0 est réintégrée ; elle reste ensuite disponible sur pending jusqu’à la prochaine synchronisation. Si un filtre de synchronisation a désactivé l’offre (par exemple en raison de l’absence d’image ou de GTIN), celle-ci ne réapparaît pas automatiquement une fois le problème résolu : renvoyer status 1.
  • Fiche produit : les validations et les données de canal ne sont désormais enregistrées qu’après un enregistrement réussi. Les données de canal d’un canal qui a été activé entre l’ouverture et l’enregistrement, par exemple via l’API, sont conservées. Le bouton lui-même est toujours réinitialisé à son état initial lors de l’enregistrement d’un masque précédemment ouvert : recharger les masques ouverts après une validation via l’API.
Produits : sélection des champs
  • Nouveau : ?fields= dans l’exportation des produits indique les clés par produit, par exemple ?fields=products_model,products_price,products_quantity; products_id est toujours inclus. Seules les données nécessaires sont chargées : lors d’un test, une page contenant 250 articles est passée de 4,3 Mo à 52 Ko. Les clés non mentionnées sont totalement absentes, au lieu d’être vides. Une sélection peut être renvoyée via PUT et ne modifie que les éléments qu’elle contient.
  • Modifié : Si vous envoyez déjà ?fields=, vous ne recevez désormais que les clés mentionnées au lieu de l’ensemble du jeu de données, avec l’avertissement UNKNOWN_FILTER. Une liste invalide génère une erreur HTTP 400 INVALID_FILTER_VALUE, un nom inconnu entraîne l’avertissement UNKNOWN_FIELD (avec ?_strict=true, erreur HTTP 400). bundle, bonus_free_features et marketplaces demandent le nom via ?fields=; le commutateur seul ne fonctionne alors pas (avertissement SWITCH_IGNORED).
Limite de requêtes
  • Nouveau : chaque réponse adressée à un client soumis à une limite de requêtes comporte les en-têtes X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset. GET /me indique à cet effet rate_limit_window, rate_limit_remaining et rate_limit_reset.
  • Modification : pour le code d'état HTTP 429, Retry-After indique le nombre de secondes jusqu'à la prochaine acceptation (de 1 à 3 600) au lieu d'une valeur fixe de 3 600, et la réponse contient error.retry_after. Le message est désormais « Rate limit of N requests per 3 600 s (sliding window) exceeded. » ; Les connexions analysent error.code, et non le texte. Au niveau du point de terminaison du jeton, Retry-After est également calculé (de 1 à 300).
Adresse de la boutique → ID
  • Nouveau : filtres précis pour les adresses de la boutique : ?seo_string= vers /categories et /seohistorys, ?seo_name= vers /products. Pour une adresse provenant de la Search Console, d’un ancien plan du site ou d’un e-mail client, on obtient ainsi la catégorie, l’article ou la destination d’une redirection. Jusqu’à présent, les noms UNKNOWN_FILTER étaient signalés, et la liste était fournie sans filtrage. Plusieurs résultats sont renvoyés. Si deux catégories partagent une même adresse, la boutique effectue le choix sans ordre défini : le premier résultat n’est pas nécessairement la page affichée.
  • Modification : DELETE /seohistory(s)?seo_string= renvoie un code HTTP 400, rien n’est supprimé. Jusqu’à présent, le nom était ignoré et seules les entrées ?type=/?base_id= étaient supprimées. Les entrées se suppriment via leur sh_id.
  • Modification : une valeur composée uniquement de virgules sur products_model, products_ean et seo_name (/products), ainsi que sur email, lastname, company et customers_id_extern (/customers) renvoie un code HTTP 400 au lieu de la liste non filtrée. Un élément vide entre les valeurs continue d’être ignoré.
Valeurs non valides
  • Modifié : GET /coupons?type= ne contenant que des virgules, par exemple une liste vide, renvoie un code HTTP 400 au lieu de la liste complète des coupons avec les codes de crédit.
  • Modification : un filtre de date composé uniquement de signes de ponctuation (?date_to=,, ?last_modified=., ?valid_on=,) renvoie un code HTTP 400 INVALID_FILTER_VALUE; auparavant, il était interprété comme « maintenant ». Cela concerne date_from et date_to vers /tickets, /contracts, /projects, /appointments et /wallet_logs, due_from et due_to vers /project_tasks, since vers /medias, last_modified vers /products et valid_on vers /coupons. Un espace vide est désormais systématiquement interprété comme « non défini ». Un « + » dans l'adresse correspond à un espace ; envoyez un « + » à l'adresse %2B.
  • Modifié : POST /media et PUT /media/{id}: un champ contenant exactement une valeur sous forme de liste (entity_id[]=5, un tableau dans le corps JSON) renvoie une erreur HTTP 400 INVALID_FIELD_VALUE avec field; rien n’est lu ni écrit. Auparavant, on obtenait une erreur HTTP 500 ou une autre valeur, comme l’image de l’article 1. Les fichiers multiples sont traités comme plusieurs appels.
  • Les réponses d'erreur contenant du code UTF-8 non valide dans un nom ou une valeur répété(e) s'accompagnent désormais d'un corps de réponse, les caractères illisibles étant remplacés par U+FFFD: noms de paramètres inconnus (avertissement UNKNOWN_FILTER, auparavant une réponse vide), les rejets liés à la validation des valeurs renvoient un 404 vers /ticket_attachment/{id} et les erreurs de POST /media sont renvoyées sous la forme multipart/form-data.
  • D'autres corrections de la validation des valeurs concernent des points de terminaison internes.
Point de terminaison des jetons
  • Modification : une portée demandée qui ne peut pas être lue (UTF-8 non valide ou une liste telle que scope[]=…) renvoie une erreur HTTP 400 invalid_scope; aucun jeton n’est émis. client_id ou client_secret sous forme de liste renvoient une erreur HTTP 400 invalid_request.
E-mails, n8n et historique des commandes
  • Les textes libres, les données client, les prix et les saisies dans les formulaires apparaissent mot pour mot dans le corps de l’e-mail, l’objet et l’historique des commandes ; un « $ » suivi d’un chiffre ne se perd plus (auparavant, « Nachnahme $100 » devenait « Nachnahme 0 »). Cela s’applique également aux e-mails qui déclenchent une intégration.
  • Le nom, la raison sociale et l’adresse issus de la commande et du compte client ne sont désormais insérés par la boutique dans les e-mails que sous forme de texte. Les nouvelles entrées de l’historique résultant de changements de statut, dont le texte utilise des espaces réservés, comportent donc ces valeurs masquées (GET /orders → status_history[].comments, par exemple Müller & Söhne), tout comme comment dans l’événement n8n order.status_changed; comment_text reste en texte clair. Les entrées existantes sont conservées.
Perspectives
  • La version 4.10 de Shop apportera, entre autres, de nouvelles fonctionnalités pour les offres groupées, le statut en temps réel par place de marché (live), ?fields= sur d’autres listes et avec des sous-clés, de nouvelles options de recherche sur /seohistorys ainsi que des renforcements de sécurité internes supplémentaires.

v2.122.10

15 octobre 2026

Deuxième partie des extensions pour les connexions au système de gestion des stocks et à l’automatisation, notamment en lecture. Comparaison numérique des numéros de version : la version 2.122.10 succède à la version 2.122.9. À partir de la version 4.9.169 de la boutique.

Clients : références de commande et paniers
  • Nouveau : chaque client dispose des indicateurs « order_stats » avec les valeurs « orders_count », « orders_count_valid », « first_order_date », « last_order_date », « first_valid_order_date » et « last_valid_order_date ». Les valeurs « valid » ne tiennent pas compte des commandes annulées ni des devis. Les interfaces strictes en termes de types de données doivent prendre en compte ce nouveau champ.
  • Nouveau : filtre ?ordered_since= sur /customers pour les clients ayant au moins une commande à partir de cette date.
  • Nouveau : GET /customers_baskets, /customers_basket/{customers_id} et la section /customers_baskets/{von}:{bis} fournissent le panier de chaque client avec les lignes, les caractéristiques, basket_last_modified et last_activity. Filtres : customer_id, since et basket_type. Un panier vide n’apparaît pas.
  • Le périmètre customers:read couvre ainsi les paniers et les indicateurs de commande. Veuillez vérifier les autorisations des clients et votre propre politique de confidentialité.
Formats de chemin d'accès et moments
  • Les formats de chemin d’accès de /orders et /customers, par exemple /order/{id}, /orders/{von}:{bis} et /orders/new:{datum}, parcourent désormais la base de données par ordre croissant d’ID. Les grandes plages ne provoquent ainsi plus d’erreur de mémoire. Sans ?limit=, la réponse reste non triée jusqu’à la limite maximale ; au-delà, elle est fournie en taille standard avec has_more.
  • Modifié : new:{datum} est vérifié (YYYY-MM-DD, YYYY-MM-DD HH:MM ou YYYY-MM-DD HH:MM:SS), sinon HTTP 400 INVALID_RANGE. Si l’heure est indiquée, la précision est à la seconde près. Ce format n’est désormais valable que pour /customer(s) et /order(s); les autres points de terminaison renvoient un code HTTP 400 et indiquent, le cas échéant, leur filtre de date.
  • Modification : les dates et heures dans les filtres doivent désormais être exprimées sous des formes fixes : YYYY-MM-DD, YYYY-MM-DD HH:MM ou YYYY-MM-DD HH:MM:SS, avec le fuseau horaire en option (Z ou ±HH:MM; envoyer le signe « + » sous la forme %2B ). Les indications telles que yesterday ou 01.10.2026 génèrent une erreur HTTP 400 INVALID_FILTER_VALUE. Cela concerne /customers, /customers_baskets, /newsletter_subscribers, /orders et /coupons.
  • Nouveau : ?last_modified= vers /orders, en tant qu’autre orthographe de since (remarque FILTER_ALIAS).
  • Modification : /customers/{von}: et /products/{von}: sont désormais des plages ouvertes à partir de l'ID indiqué. Auparavant, les deux ne renvoyaient qu'un seul enregistrement.
Paramètres de requête non valides
  • Modification : les valeurs non valides et les valeurs de liste (?x[]=, ?x[k]=) génèrent une réponse HTTP 400 INVALID_FILTER_VALUE avec details[] sur tous les points de terminaison JSON. La validation s'effectue avant toute lecture, écriture ou suppression. Jusqu’à présent, un tel filtre était parfois omis, et la réponse contenait le contenu non filtré. Les valeurs valides restent inchangées, une valeur vide est considérée comme non définie.
  • À l'adresse /orders, une liste séparée par des virgules, un texte ou un nombre décimal renvoie une erreur HTTP 400 aux adresses status, customer_id, marketplace_id, products_id et categories_id. Plusieurs pays de livraison sont indiqués sous forme de liste séparée par des virgules à l'adresse delivery_country.
  • /categories/productlist accepte categories_id et include_inactive_products sans avertissement. parent_id et recursive ne fonctionnent pas à cet endroit et renvoient UNKNOWN_FILTER.
Abonnés à la newsletter
  • Modification : l'envoi de ?last_modified= à /newsletter_subscribers fournit également les abonnés ayant confirmé leur inscription par double opt-in ou dont le transfert vers le prestataire de la newsletter est encore en attente. Le delta s'en trouve ainsi accru. Les adresses supprimées et désabonnées ne figurent dans aucun delta ; il est donc recommandé de procéder régulièrement à une synchronisation complète.
  • Nouveau : customer_id et language_id sous forme de liste séparée par des virgules. ?email= continue de rechercher une partie de l’adresse, tandis que % et _ sont considérés comme des caractères. La liste parcourt la base de données.
Produits
  • Nouveau : données bonus et gratuites de l’article sous forme de bloc bonus_free_features (status_bonus, bonus_points, max_bonus, status_free, bonus_value, max_free, auto_free). L’exportation ne les fournit qu’avec ?bonus_free_features=1. Lors de l’importation, une clé manquante laisse les données inchangées, null les supprime, un objet ne modifie que les champs envoyés. Les valeurs non valides entraînent le rejet de l'enregistrement (INVALID_BONUS_FREE_FEATURES), le blocage d'importation bonus est respecté.
  • Modifié : un article inexistant renvoie, lors d’une requête individuelle (/product/{id}), un code HTTP 404 NOT_FOUND au lieu d’un code HTTP 200 avec une entrée vide data.
  • Modification : les articles sans image principale ne renvoient plus d’entrée d’image vide (images_id 0). Les exportations plus anciennes contenant cette entrée peuvent être renvoyées sans erreur ; l’image principale enregistrée est conservée.
  • Modification : products_status ne peut prendre que la valeur 0 ou 1. La boutique définit elle-même le statut 2 lorsque l’article ne dispose pas d’un chemin de catégorie actif de bout en bout (avertissement NO_ACTIVE_CATEGORY_PATH). Une valeur 2 envoyée ou une valeur non valide n’est pas enregistrée (READONLY_VALUE ou INVALID_FIELD_VALUE). Nouveauté dans la réponse : records[].products_status.
  • Modification : « products_xoport » accepte au maximum 64 caractères. Une valeur plus longue entraîne le rejet de l'enregistrement, au lieu d'être raccourcie en silence.
  • Nouveau : blocage d’importation cost pour le prix d’achat, configurable via import_blocks. Vérifier au préalable api_version: les boutiques plus anciennes n’enregistrent pas ce type, et jusqu’à la version 2.122.8, une liste ne supprime que les blocages existants de cost.
Bons d'achat
  • Nouveau : la commande ?last_modified= vers /coupons fonctionne sans avertissement, même avec ?_strict=true.
  • Modification : les valeurs de liste dans les filtres de bons et les dates hors des formats prédéfinis génèrent une erreur HTTP 400 au lieu d’afficher la liste complète des bons. Les copies issues de la fonction « Copier un bon » apparaissent dans le delta avec leur date de création.
Statut de la commande
  • Nouveau : GET /order_statuses, /order_status/{id} et les sections fournissent tous les statuts de commande avec des noms par langue, des couleurs, un tri et les indicateurs is_default, is_cancelled, is_offer, counts_as_revenue, is_paid et is_shipped. Portée : orders:read; un statut inexistant renvoie une erreur HTTP 404.
n8n et les entrées plus anciennes
  • Modifié : l’événement n8n order.status_changed contient désormais également comment_text en texte clair. comment contient le texte de l’entrée d’historique avec les espaces réservés remplacés ; les messages contenant $ sont conservés tels quels.
  • Supprimé : les anciennes entrées api/n8n/ et api/order-status.php renvoient une réponse HTTP 404. Les changements de statut s'effectuent via PUT /Import/JSON/orders.
Portes CSV et XML
  • Rubrique CSV « Module Bonus/Gratuit » : une cellule vide définit la valeur sur 0, une colonne manquante la laisse inchangée. Les catégories ayant le statut del suppriment toute la branche.
  • Importation de produits au format XML : un nœud vide <bonus_free_features> laisse le statut « Bonus » et « Gratuit » inchangé, tandis qu’un 0 explicite le désactive.

v2.122.9

13 octobre 2026

Première partie des extensions pour les connexions à la gestion des stocks et à l’automatisation. À partir de la version 4.9.168 de la boutique.

Commandes
  • Nouveau : filtre ?delivery_country= à /orders avec les codes pays ISO, à deux ou trois chiffres et séparés par des virgules. Un code inconnu renvoie une erreur HTTP 400 INVALID_FILTER_VALUE.
  • Modification : les filtres appliqués à une forme de chemin de type /order(s) s’appliquent désormais en plus de la forme de chemin. Auparavant, ils la remplaçaient : /order/{id}?status=3 renvoyait toutes les commandes ayant le statut 3.
Produits
  • Modification : l’exportation des produits ne contient que les articles de la requête, aucun élément sans products_id. Les éléments de type xsells sont exportés dans leur intégralité et placés après sort_order; les éléments de type unit_single, unit_multi et unit_base sont renseignés, tandis que ceux sans unité sont laissés vides au lieu de null. L’exportation personnalisée peut être renvoyée via ?_strict=true; les champs en lecture seule sont signalés par READONLY_FIELD.
  • Modification : une liste import_blocks sans entrée exploitable ne modifie plus les blocages ; auparavant, tous étaient supprimés. Tous les types de blocage de la boutique peuvent être définis. Nouveauté : import_blocks_mode (replace, merge ou append, remove) et records[].import_blocks. Les anciennes boutiques ignorent ce mode ; il faut donc l'envoyer uniquement avec ?_strict=true.
  • Modifié : un categories_mode invalide, une catégorie inconnue, un categories ou un images sans liste, ainsi qu’un images[] sans entrée valide entraînent le rejet de l’enregistrement avant son écriture (INVALID_CATEGORIES_MODE, INVALID_CATEGORIES, INVALID_IMAGES). Auparavant, il était parfois enregistré. Chaque rejet est répertorié avec son code dans records[].
  • Modification : options_replace, options_strict_names, apply_value_defaults, videos_replace et customers_prices_replace ne s’activent qu’avec true, 1, "1" ou "true"; "false" et "no" ne s’activent plus.
  • Nouveau : les téléchargements d’images (POST /media, PUT /media/{id} avec fichier) signalent replaced_existing et thumbnails_removed. Un cache en amont tel que Cloudflare n’est pas vidé dans ce cas ; sur replaced_existing: true, actualisez vous-même l’adresse de l’image.
  • L'importation de produits avec MPN ne se termine plus par une erreur HTTP 500 sur les boutiques non connectées à eBay. Après une importation depuis shop_ids sous forme de liste, l'interface d'administration affiche correctement les boutiques associées.
Bons d'achat
  • Modification : restrictions.categories contient désormais également des catégories enregistrées avec des sous-catégories ; la nouvelle adresse est restrictions.categories_with_subcategories. Les intégrations voient ainsi davantage d’identifiants de catégories.
  • Modification : coupon_code reste du texte, même pour les codes purement numériques tels que « 4711 ». Vérifiez les comparaisons de type exact.
Configuration
  • Modifié : les identifiants d’accès, les clés de licence, de session et d’interface, ainsi que les paramètres internes, ne sont ni lisibles ni modifiables via /configuration, même s’ils sont partagés (CONFIG_KEY_BLOCKED). Retirez ces clés de la liste de partage ; si des identifiants d’accès étaient partagés, renouvelez-les auprès du fournisseur.
  • Modifié : PUT /configuration n'écrit que du texte en clair et des nombres entiers dans les limites du masque du backend. Les clés qui déclenchent une action consécutive dans le backend sont en lecture seule et sont modifiées dans le backend.
Abonnés à la newsletter
  • Modification : POST /newsletter_subscribers rejette les adresses faisant l’objet d’un blocage de la newsletter ou d’une opposition à la publicité (NEWSLETTER_LOCKED, OPTED_OUT ou NOT_SUBSCRIBABLE). Les adresses désabonnées ne peuvent être réabonnées qu’avec send_doi.
  • Modification : dans la boutique « double opt-in », une requête POST sans subscribe_confirm envoie elle-même l'e-mail de confirmation, à raison d'un maximum d'un par adresse toutes les 24 heures.
  • Nouveau : send_doi, records[].confirmed et records[].doi_mail. subscribe_confirm n’accepte qu’une date/heure ou une réponse oui/non. La requête PUT ne confirme plus rien (FIELD_IGNORED_ON_UPDATE).
  • Modification : DELETE /newsletter_subscriber(s) vérifie le résultat auprès du fournisseur de la newsletter. Si la désinscription échoue à ce niveau, le chemin unique renvoie un code HTTP 502 NEWSLETTER_UNSUBSCRIBE_FAILED.
  • Importation de clients au format XML : <newsletter>0 désabonne l'adresse et enregistre une opposition à la publicité.
n8n, webhooks et envoi
  • Modification : order.status_changed n’est utilisé qu’en cas de changement de statut réel ; désormais avec old_status. Les événements ne sont envoyés qu’une fois que la modification signalée a été enregistrée. La signature est générée comme auparavant à partir du contenu envoyé ; l’exemple de vérification de la documentation a été corrigé.
  • La réaction marketing « Envoyer un webhook » se répète après un échec, au lieu de bloquer la cible.
  • compute_shipping Pour une valeur de marchandise égale à 0, elle renvoie la ligne d’expédition au lieu de l’avertissement « SHIPPING_AUTO_FAILED ».
Interface XML
  • Modification : « <products_to_marketplaces> » sans entrées n’a plus d’effet ; auparavant, toutes les autorisations étaient mises à 0. Les entrées ne s’appliquent qu’aux places de marché connues et sous licence ayant le statut 0 ou 1. Les flux qui souhaitaient tout désactiver à l’aide d’un nœud vide envoient désormais des entrées avec le statut 0. Nouveau bloc de réponse « marketplaces ».

v2.122.8

11 octobre 2026
Corrections de bogues
  • Enregistrement des commandes (orders:write) : les lignes de commande présentant un montant de taxe négatif, comme les remboursements, disposent désormais de leur propre ligne de taxe. Lors de l’ajout de lignes de commande via PUT, la taxe des lignes négatives est prise en compte ; auparavant, le total était trop élevé.
  • Lors de la création de nouveaux postes de commande, le système vérifie, comme lors du paiement, s’il s’agit de marchandises ou d’un service. Les documents relatifs aux livraisons et prestations intracommunautaires restent ainsi cohérents.
  • /cms, /faqcats et /faqs: les filtres ?status= et ?module= (uniquement /cms) renvoyaient une erreur HTTP 500 sans format de chemin. Désormais, le filtrage s’effectue sans avertissement UNKNOWN_FILTER. ?module= est le code exact du module.
  • DELETE /customer Anonymise au préalable l'historique des produits consultés par le client.
  • Importation de catégories XML : les champs vides ne remplacent plus rien. La réponse mentionne en outre categories{inserted, updated, unchanged, deleted, paths_changed, cyclic_parents}.
  • Importateur CSV : l’importation des caractéristiques définit le statut pour l’ensemble de la chaîne de caractéristiques. Les flux convertissent les montants en devises étrangères. À partir de la version 4.9.167 de la boutique.

v2.122.7

6 octobre 2026
Les blocages des groupes de clients lors de l’importation
  • restricted_customer_groups sur les produits et les catégories ne prend en compte que les groupes de clients existants, sous forme de nombre entier. Si la liste ne contient aucun groupe existant ou s’il ne s’agit pas d’une liste, les blocages enregistrés restent inchangés (avertissement CUSTOMER_GROUP_RESTRICTION_KEPT). Un article nouvellement créé lors de cette opération ne présente aucun blocage.
  • La présence d’entrées inconnues à côté d’entrées connues déclenche l’avertissement « CUSTOMER_GROUP ». La commande « [] » continue de lever toutes les restrictions ; les listes valides fonctionnent comme auparavant. La même règle s’applique dans le CSV-Porter. À partir de la version 4.9.155 de la boutique.

v2.122.6

6 octobre 2026
Exporter les avis sur les produits
  • Nouveau : GET /reviews, GET /review/{reviews_id} et la section GET /reviews/{von}:{bis} avec la portée products:read. Jusqu’à présent, l’API ne fournissait pour chaque produit que la moyenne et le nombre d’avis (products_rating, products_rating_count).
  • Par avis : reviews_id, products_id, products_model, reviews_rating, status, promo_status, author, verified_purchase, helpful_count, review_external_id, date_added, last_modified et descriptions[]; par langue avec reviews_title, reviews_text et reviews_reply (réponse de la boutique).
  • Filtres : products_id (également sous forme de liste séparée par des virgules), status (1 = validé, valeur par défaut ; 0 = en attente de validation ; all) et since (créé ou dernière modification à partir de). La navigation s'effectue comme pour les produits avec limit et page.
  • Pas de données client : author est le nom qui s'affiche également sur la page du produit. Le point de terminaison ne fournit pas l'identifiant client, l'adresse e-mail ni le numéro de commande, mais uniquement verified_purchase. À partir de la version 4.9.153 de la boutique.

v2.122.5

1er octobre 2026
Interface XML : exportation des produits et des fournisseurs
  • L'exportation XML des produits s'interrompait avec un code HTTP 500 dès qu'un article ne figurait pas encore dans l'index de recherche rapide. Ces articles sont désormais exportés normalement ; l'exportation JSON n'était pas concernée.
  • L’importation de produits au format XML synchronise désormais le nœud « suppliers » au lieu de supprimer puis de recréer les fournisseurs. La référence fournisseur des fournisseurs permanents est conservée. À partir de la version 4.9.139 de la boutique.

v2.122.4

30 septembre 2026
Fonctionnalités et tickets
  • Caractéristiques : « options[].cost » est désormais un autre nom pour « ext_cost ». Auparavant, un prix d’achat écrit de cette manière aboutissait à un emplacement que ni la page produit, ni la page de paiement, ni l’éditeur ne lisaient. Si les deux sont envoyés, c’est « ext_cost » qui s’applique. Le prix d’achat et le prix de vente conseillé sont vérifiés en tant que montants ; les valeurs non valides déclenchent l’avertissement « OPTION_META_INVALID ».
  • Tickets : DELETE /tickets supprime désormais toutes les données associées au ticket, telles que les responsables, les abonnés, les liens vers les rendez-vous et les projets. À partir de la version 4.9.135 de la boutique.

v2.122.3

30 septembre 2026
Création de commandes : prix en cas de calcul brut
  • orders:write avec tax_flag = 1: les prix calculés par la boutique (recalc) et les frais de port provenant de compute_shipping sont des montants nets. Jusqu’à présent, ils étaient comptabilisés comme des montants bruts, la taxe n’apparaissant pas dans le total. Désormais, ils sont extrapolés. Les prix que vous envoyez vous-même restent bruts, comme auparavant.
  • Si vous avez adapté expected_total à un montant trop bas, vous recevez désormais l'avertissement TOTAL_DRIFT (avec strict_totals HTTP 422).
  • Les suppléments de formule des caractéristiques standard (apply_default_attributes) sont calculés comme sur la page du produit. Jusqu’à présent, une formule donnait 0 €. Les formules que seule la page du produit peut évaluer génèrent l’avertissement « DEFAULT_ATTRIBUTE_FORMULA ». À partir de la version 4.9.134 de la boutique.

v2.122.2

29 septembre 2026
Clients : modification partielle des adresses sans que le pays ne revienne à sa valeur initiale
  • PUT /Import/JSON/customers avec addresses[] et address_book_id (ou l’objet address), seuls les champs envoyés sont désormais mis à jour. Jusqu’à présent, toute mise à jour sans indication de pays définissait le pays sur celui de la boutique et la zone sur 0. Une simple mise à jour de la rue transformait ainsi une adresse autrichienne en une adresse allemande.
  • Le pays et la zone ne changent que si vous les transmettez. En cas de pays inconnu, la réponse signale l’avertissement ADDRESS_COUNTRY. Une mise à jour conserve alors le pays enregistré, tandis qu’une nouvelle adresse reçoit, comme auparavant, le pays de la boutique.
  • Autre correction : les apostrophes étaient enregistrées avec une barre oblique inversée, et les valeurs trop longues étaient tronquées octet par octet sans avertissement. Désormais, la troncature s’effectue caractère par caractère, avec l’avertissement « ADDRESS_TRUNCATED ». Les chiffres dans « entry_country » ne sont pas considérés comme des identifiants de pays.
  • Boutiques utilisant une version antérieure : veillez à toujours indiquer le pays lors des mises à jour d’adresse. À partir de la version 4.9.132 de Shop.

v2.122.1

27 septembre 2026
Sécurité : exportation des clients et des commandes sans données de mot de passe
  • Les exportations /customers et /orders (JSON et XML) ne fournissent plus le hachage du mot de passe ni les jetons pour la réinitialisation du mot de passe et la suppression du compte : customers_password, customers_password_request, customers_password_request_time et customers_hash sont supprimés sans remplacement.
  • De plus, l'enregistrement client ne contient plus de « iban » ni de « bic ». Dans l'enregistrement de commande, ces deux champs sont conservés. À partir de la version 4.9.123 de la boutique.

v2.121.0

19 septembre 2026
L'importation des actualités crée les langues manquantes
  • POST /Import/JSON/newsdesk complète, lors de la création, chaque langue active pour laquelle aucun bloc spécifique n’a été envoyé, à partir de la langue principale (le bloc « de », ou sinon le premier bloc envoyé). Si la traduction DeepL est configurée, elle traduit ces langues lors de la prochaine exécution. Jusqu’à présent, un article créé uniquement avec « de » restait définitivement monolingue.
  • Les textes modifiés au format imbriqué « languages » sont désormais également retraduits. À partir de la version 4.9.106 de la boutique.

Les numéros de version 2.119.1, 2.121.1 et 2.122.0 concernent des points de terminaison internes ; la version 2.120.0 n’a pas encore été publiée.

v2.119.0

18 septembre 2026
API REST : toujours avec un jeton, avec en option une restriction supplémentaire aux adresses fixes
  • Important : l’autorisation IP de l’interface XML (XML_PORT_IP_FILTER) ne donne plus accès à l’API JSON/REST. REST exige toujours un jeton OAuth2, et ce sont ses champs d’application qui s’appliquent. Un client qui utilisait jusqu’à présent REST sans jeton, uniquement via une adresse autorisée, recevra le message « 401 » avec « reason: deny_token_required ».
  • Le paramètre XOPORT_REST_IP_LIST constitue une nouvelle mesure de sécurité supplémentaire. S’il est renseigné, toute requête doit provenir d’une adresse figurant dans la liste et comporter un jeton valide, faute de quoi la réponse 403 s’affiche avec reason: deny_ip_not_listed.
  • Si l’API rejette une requête, elle indique le motif dans le champ « reason » et dans l’en-tête « X-XoPort-Deny-Reason ». L’interface XML reste inchangée. À partir de la version 4.9.83 de la boutique.

v2.118.1

17 septembre 2026
Tickets : plus d’avertissement erroné pour les rendez-vous liés
  • linked_appointments Les champs POST/PUT /Import/JSON/tickets généraient en outre l'avertissement « UNKNOWN_FIELD » (« will be ignored »), bien que les rendez-vous soient créés depuis la version v2.43.0. Cet avertissement a été supprimé, mais le traitement reste inchangé. À partir de la version 4.9.75 de Shop.

v2.118.0

17 septembre 2026
Tickets : demande de traitement
  • Le nouveau point de terminaison PUT /Import/JSON/ticket_claims (portée tickets:write) indique qui travaille actuellement sur un ticket. Champs obligatoires : ticket_id, admin_id et state (claimed ou released), champs facultatifs : ttl_minutes (valeur par défaut 60, de 5 à 240), label et force.
  • Résultat par enregistrement dans records[].status: claimed, refreshed, taken_over, released, unchanged ou conflict. ⚠ Un conflit est représenté par failed.
  • GET /tickets et GET /ticket/{id} renvoient les nouveaux champs claim et edit_lock (le ticket est actuellement ouvert dans le backend), ainsi que null dans tous les cas où aucune information n’est disponible.
  • Une réponse publique (via l’API ou dans le backend) et le passage à un statut « fermé » valident automatiquement la réclamation, contrairement à une note interne. La réclamation est une remarque, pas un blocage, et ne modifie ni ticket_date_last_modified ni l’historique. À partir de la version 4.9.73 de Shop.
  • Les numéros de version v2.116.0 et v2.117.0 font partie des nouveautés qui seront disponibles avec la prochaine mise à jour de fonctionnalités ; ils seront alors ajoutés ici.

v2.115.0

15 septembre 2026
Les importateurs XML vérifient le fichier de flux lors du chargement
  • Si un fichier contient des caractères interdits par XML 1.0 (par exemple, des caractères de contrôle dans les textes descriptifs), les huit importateurs XML suppriment ces caractères et traitent le fichier. Jusqu’à présent, un tel fichier renvoyait 0 enregistrement, était néanmoins archivé et la réponse indiquait que l’opération avait réussi.
  • Si un fichier reste illisible après cette opération, il est déplacé vers xoport/xml/import/error/ au lieu d’être archivé, puis supprimé à l’issue du délai de conservation, tout comme l’archive.
  • Nouveaux champs de réponse : outcome (ok, partial, failed), files.failed et warnings.invalid_xml_chars_removed. files.processed.filenames ne mentionne plus les fichiers rejetés.
  • ⚠ Si tous les fichiers d'un cycle échouent, l'importation renvoie « "state": "error" » et le code HTTP 422. Les interfaces qui analysent le statut HTTP détectent ainsi un tel échec pour la première fois ; vous pouvez identifier les fichiers refusés individuellement grâce à « outcome: "partial" ». À partir de la version 4.9.65 de Shop.

v2.114.0

14 septembre 2026
Produits exclus des bons de réduction
  • GET /coupons et GET /coupon/{id} fournissent le nouveau champ restrictions.excluded_products: les identifiants de produits qui ne bénéficient jamais d’une réduction via ce bon de réduction.
  • Cette exclusion s’applique en plus de toutes les autres restrictions et prévaut sur restrictions.products. Un article principal exclu inclut ses variantes, tandis qu’une variante exclue n’inclut qu’elle-même.
  • Les coupons sans exclusion renvoient une liste vide [].

v2.113.1

14 septembre 2026
Coupons : correction de restrict_mode
  • ⚠ Jusqu’à présent, restrict_mode était exporté à l’envers. La correction est la suivante : allow_only = uniquement les articles des catégories listées, deny = tous sauf ceux-ci, sauf si l’article se trouve également dans une catégorie non listée, désormais deny_strict = tous sauf les articles se trouvant dans une catégorie listée quelconque.
  • Ce champ décrit exclusivement restrictions.categories. restrictions.products et restrictions.manufacturers sont toujours des listes positives ; si la liste des produits est renseignée, les catégories et les fabricants ne sont pas pris en compte.
  • Si vous exploitez ce champ depuis la version v2.102.0, veuillez vérifier votre affectation.

v2.113.0

13 septembre 2026
Attribution d’un numéro de facture via l’interface
  • Nouveau champ « assign_invoice_number » sur POST et PUT /Import/JSON/orders: avec « true », la boutique attribue le prochain numéro de sa série de numéros de facture. Le numéro lui-même ne peut pas être défini et est ensuite immuable.
  • La réponse indique « invoice_number_assigned » ; en cas de succès, elle renvoie également « invoice_id_individuell » et « invoice_date ». Dans le cas contraire, « invoice_number_reason » indique la raison (mode_disabled, already_assigned, locked), accompagnée de l'avertissement « INVOICE_NUMBER_NOT_ASSIGNED ».
  • Les attributions simultanées sont bloquées les unes par rapport aux autres. Si vous obtenez le message « locked », cela signifie que la boutique a délibérément choisi de ne pas attribuer de numéro plutôt que d’en attribuer un en double ; dans ce cas, veuillez réitérer votre requête.

v2.112.0

13 septembre 2026
Nouvelles catégories avec les paramètres du masque d’administration
  • ⚠ Si vous créez une catégorie sans sitemap ou shop_ids, les mêmes valeurs que celles du masque d’administration s’appliquent désormais : sitemap = 1 et toutes les boutiques sous forme de liste complète. Jusqu’à présent, les paramètres des colonnes s’appliquaient (pas de plan du site, pas d’affectation de boutique).
  • L'avertissement CATEGORY_DEFAULTS_APPLIED indique les valeurs définies. Les mises à jour des catégories existantes ne sont pas concernées.

v2.111.0

13 septembre 2026
Supprimer les vidéos et les numéros d'expédition
  • videos[]: supprimer des entrées individuelles avec _action: "delete", ou utiliser videos_replace: true pour reprendre la liste envoyée dans son intégralité (uniquement sur demande expresse). Le fichier vidéo lui-même est conservé, seule l'affectation est supprimée.
  • trackings[]: _action: "delete" via id_tracking ou service_provider et code. Un numéro d’expédition peut ainsi être supprimé et recréé en une seule opération.
  • Dans les deux cas, vérifiez que l’entrée correspond bien au produit ou à la commande indiqués.

v2.110.0

13 septembre 2026
Caractéristiques d'un poste de commande existant
  • products_mode: "update" accepte désormais attributes. La liste envoyée remplace intégralement les caractéristiques du poste, tandis que [] les supprime toutes.
  • Une majoration différente ne modifie pas le prix du poste – l’interface affiche un avertissement dans ce cas. Si le prix doit être modifié, annulez le poste et rajoutez-le.
  • La modification est bloquée pour les commandes déjà facturées, car les caractéristiques figurent sur la facture et le bon de livraison.

v2.109.0

13 septembre 2026
Lecture et activation des fichiers CSV/XLS
  • Nouveau : GET /Export/JSON/porters, /porter/{id} et PUT /Import/JSON/porters avec les portées porters:read et porters:write.
  • active définit l'état (true = actif par la suite) au lieu de le basculer. Sans active, l'appel est rejeté. Lors de la désactivation, la boutique supprime le fichier d'exportation généré, comme dans le backend.
  • L'appel unique fournit, à l'adresse columns, le mappage complet des colonnes du Porter.

v2.108.0

13 septembre 2026
Lire et modifier les paramètres
  • Nouveau : GET /Export/JSON/configuration et PUT /Import/JSON/configuration avec les scopes configuration:read et configuration:write.
  • ⚠ Seules les clés que l’administrateur partage dans XOPORT_CONFIG_API_KEYS sont visibles – par défaut, la liste est vide. Les identifiants d’accès, les paramètres de licence et de session restent verrouillés même lorsqu’ils sont partagés.
  • Seules les clés existantes peuvent être modifiées ; chaque modification est consignée. L'avertissement SHOP_OVERRIDE_ACTIVE signale un remplacement de domaine qui remplace la valeur de base modifiée.

v2.107.0

13 septembre 2026
Responsable dans l’historique de la commande
  • user_id d’une commandePUT indique le responsable de l’opération dans l’entrée de l’historique. Seul un identifiant de responsable existant est repris.
  • customer_notified Le message continue d’être rédigé, mais l’interface signale, via NO_MAIL_SENT, qu’elle n’envoie pas elle-même d’e-mail de statut.

v2.106.0

13 septembre 2026
Téléchargement de vidéos de produits, d’images d’options et de sous-dossiers
  • Téléchargement de médias via entity_type: "product_video" (jusqu’à 100 Mo) et entity_type: "option" pour les images d’options.
  • subfolder Enregistre les images dans un sous-dossier (un niveau, minuscules, chiffres, _ et -).
  • L'extension de fichier est déterminée à partir du type de fichier détecté, et non à partir du nom de fichier envoyé.

v2.105.0

13 septembre 2026
L'exportation des produits peut être renvoyée
  • 68 champs de produit supplémentaires sont modifiables, notamment les prix dégressifs avec seuils de quantité, le commutateur eBay ebay_allowed (module eBay classique), le blocage Amazon Pay amazon_allowed, la classification FSK 18, les marchandises soumises à des restrictions, le prix de vente conseillé, les points bonus et la date d’acquisition.
  • 14 champs en lecture seule sont signalés comme READONLY_FIELD au lieu d’être rejetés sans commentaire.
  • ⚠ Les valeurs non valides (valeur de sélection inconnue, texte trop long, chiffre illisible) rejettent l’enregistrement au lieu de l’écrire à moitié. Les champs Oui/Non envoyés vides restent inchangés.
  • Correction : il était initialement écrit ici « les boutons de la place de marché ». amazon_allowed n’est toutefois pas un bouton de la place de marché, mais le verrouillage d’Amazon Pay : 1 masque les boutons Express d’Amazon Pay tant que l’article se trouve dans le panier. La signification des champs est indiquée sous « Produits », section « Autres champs de produit ».

v2.104.0

13 septembre 2026
Les images de produit remplacées reçoivent de nouvelles vignettes
  • Si une image est remplacée sous le même nom de fichier, la boutique supprime les vignettes associées, quel que soit leur format. La réponse indique thumbnails_removed et replaced_existing.
  • Les entrées dans videos[] sont vérifiées pour détecter d’éventuels noms de champs inconnus ; avec ?_strict=true, une faute de frappe entraîne une erreur HTTP 400.

v2.103.0

13 septembre 2026
Services de gestion des tickets
  • Nouveau : GET /Export/JSON/ticket_departments (?active=), /ticket_department/{id}, POST/PUT /Import/JSON/ticket_departments et DELETE /Delete/JSON/ticket_department/{id}.
  • Les sections sont multilingues ; les langues vides reprennent le nom de la langue par défaut.
  • Si un ticket est encore attribué à un service, la suppression renvoie la réponse « 409 DEPARTMENT_IN_USE ». « ?reassign_to={id} » réattribue d’abord les tickets, tandis que « ?force=1 » procède quand même à la suppression.

v2.102.0

13 septembre 2026
Bons d'achat et coupons au format JSON
  • Nouveau : GET /Export/JSON/coupons et /coupon/{id} avec les filtres ?code=, ?type=, ?active=, ?kind= et ?valid_on=.
  • Les restrictions sont fournies sous forme de listes d’identifiants, ainsi que les champs lisibles restrict_mode et is_credit_voucher. La valeur « 0 » pour les limites d’utilisation signifie « illimité ».
  • Corrigé : le nom et la description d’un coupon manquaient jusqu’à présent dans l’exportation.

v2.101.0

13 septembre 2026
L'exportation XML vérifie les autorisations
  • ⚠ Un jeton OAuth2 à portée restreinte reçoit désormais, dans l’export XML, la mention « 403 » pour les domaines sans autorisation : customers:read, orders:read (également pour les bons d’achat), products:read, categories:read, manufacturers:read.
  • Les connexions via AppKey ou l'autorisation par adresse IP ne sont pas concernées.

v2.100.0

13 septembre 2026
Configuration des filtres des pages de catégories
  • Nouveau : GET /Export/JSON/products_filters et /products_filter/{fid} avec ?options_id= et ?categories_id= – quels filtres une page de catégorie propose.
  • Remarque : la version 2.100.0 succède à la version 2.99.0. Comparez les versions à l'aide de version_compare(), et non sous forme de nombre décimal.

v2.99.0

13 septembre 2026
Exportation de clients avec filtres et pagination
  • Nouveaux filtres sur /customers: customers_id, customers_group_id, language_id, email, lastname, company, customers_id_extern, les filtres de préfixe email_prefix, lastname_prefix, company_prefix ainsi que purchased_without_account, sort, order et page.
  • Les bases de données clients volumineuses sont parcourues au fur et à mesure plutôt que chargées dans leur intégralité.
  • Une valeur de filtre invalide entraîne l'erreur « 400 INVALID_FILTER_VALUE » au lieu d'être simplement ignorée.

v2.98.0

12 septembre 2026
Numéros d’expédition, demande d’évaluation, champs de position
  • trackings (au pluriel, comme dans l’export) sont pris en compte. Les numéros d’expédition en double sont ignorés et signalés ; un lien manquant est complété à partir du prestataire de services d’expédition.
  • rating_mail est modifiable.
  • products_mode: "update" Modifie les champs des lignes existantes (prix d'achat, nom, référence, EAN, unité, profil d'expédition, champs de date). Les quantités, les prix et le taux d'imposition sont rejetés.

v2.97.0

12 septembre 2026
Supprimer les pièces jointes du ticket, renvoyer l'e-mail
  • Nouveau : DELETE /Delete/JSON/ticket_attachment/{tshid}?filename=.
  • notify_history_id L'adresse PUT /Import/JSON/tickets renvoie l'e-mail de réponse correspondant à une entrée existante de l'historique, sans en créer une nouvelle.
  • apply_value_defaults Reprend les valeurs par défaut de l’option lors de la première attribution d’une caractéristique (sur demande expresse, car les valeurs par défaut peuvent entraîner un supplément).

v2.96.0

12 septembre 2026
Caractéristiques et valeurs d’option en tant que points de terminaison distincts
  • Nouveau : GET /Export/JSON/products_options, /products_option/{id}, /products_options_values ainsi que POST/PUT /Import/JSON/products_options.
  • values[] Cette liste n'est pas exhaustive : seules les entrées portant la valeur « _action: "delete" » sont supprimées ; « _action: "attach" » partage une valeur existante.
  • ⚠ Une option_id inconnue lors de l’importation de produits est désormais rejetée avec le message « OPTION_NOT_FOUND », au lieu de créer silencieusement une caractéristique.

v2.95.0

12 septembre 2026
Supprimer des entrées individuelles de l'historique
  • Nouveau : « DELETE /Delete/JSON/order_status_history/{id} » et « DELETE /Delete/JSON/ticket_status_history/{id} ». Le statut de la commande ou du ticket est mis à jour comme indiqué dans le masque.
  • L'entrée la plus ancienne d'une commande est protégée (409 FIRST_HISTORY_ENTRY).

v2.94.0

12 septembre 2026
Profils de délais de livraison
  • Nouveau : /shipping_profiles et /shipping_profile/{id} en lecture et en écriture, avec des niveaux, des plages de délais de livraison et des textes personnalisés par langue.
  • Au niveau du produit, l’exportation fournit en outre shipping_profile_effective, _name, _step et _text.

v2.93.0

12 septembre 2026
Recherche rapide et adressage via l’ID du produit
  • Les produits créés ou modifiés via l’interface sont intégrés à la recherche rapide. L’exportation affiche l’état de l’index par langue à l’adresse quicksearch.
  • Corrigé : une requête PUT avec products_id pouvait se solder par une erreur HTTP 500, et les modifications d’adresse ne généraient pas de redirection par ce biais.

v2.92.0

12 septembre 2026
Règles d'options du configurateur
  • options_rules[] sur le produit, en lecture et en écriture. Si le champ est absent, les règles existantes restent inchangées.
  • L'exhaustivité des blocs de règles actifs est vérifiée avant l'écriture ; sans la licence correspondante, l'opération est refusée.

v2.91.0

12 septembre 2026
Historique des statuts et textes des justificatifs pour chaque commande
  • L'exportation des commandes fournit status_history[] avec toutes les entrées d'historique.
  • indiv_text0 Les champs « bis indiv_text4 » (textes de remplacement par document) ainsi que « indiv_rg » et « indiv_ls » (noms de fichiers des PDF enregistrés) sont modifiables.
  • Les avertissements d'un fichier « commande » (PUT ) s'affichent désormais au niveau de l'entrée correspondante dans records[].

v2.90.0

12 septembre 2026
Classes d'imposition et détails des tickets
  • Nouveau : GET /Export/JSON/tax_classes et /tax_class/{id} indiquent les taux d’imposition par zone fiscale.
  • L'historique des tickets fournit l'ID de message des e-mails reçus et ticket_event_type.
  • Corrigé : une simple modification du titre de la vidéo entraînait une erreur HTTP 500.

v2.89.0

12 septembre 2026
Les succès partiels sont signalés
  • Corrigé : lors de l’ajout de lignes, un code langue pouvait apparaître sur la facture à la place du titre fiscal.
  • Sans admin_id valide, aucune entrée n’est désormais créée dans l’historique des tickets.
  • outcome Signale partial lorsqu’une partie de la commande a été refusée. Autre nouveauté : ?order_id= est désormais envoyé à /tickets.

v2.88.0

12 septembre 2026
Onglets « Produits » multilingues
  • tabs est prise en charge dans les formats plat, imbriqué par langue et d’exportation ; l’exportation fournit un bloc languages par onglet.
  • Les nouvelles catégories sans sitemap/shop_ids s'affichent avec CATEGORY_DEFAULTS_APPLIED.

v2.87.0

12 septembre 2026
Les frais et la référence de commande sont modifiables
  • handling_fee, transaction_fee, selling_fee, other_fee et po_number peuvent être définis via POST et PUT.
  • Les montants hors de la plage de valeurs et les références trop longues sont rejetés plutôt que raccourcis. Le filtre ?po_number= sur /orders est une nouveauté.

v2.86.0

12 septembre 2026
Parcourir et trier
  • ?sort= et « ?order= » vers « /orders » et « /products » ; « ?page= » a été mis en œuvre et est confirmé sous la forme « stats.page ».
  • page L'utilisation conjointe de offset entraîne une erreur. Une spécification tronquée de limit renvoie LIMIT_CAPPED.

v2.85.0

12 septembre 2026
Prix spéciaux entièrement inclus dans l'exportation
  • Les prix spéciaux sans étiquette manquaient jusqu’à présent dans l’exportation. Désormais, tous les champs sont inclus, y compris le groupe de clients, la période, l’étiquette et le type.
  • Les produits nouvellement créés portent la mention « products_last_modified » et apparaissent ainsi dans le filtre de modification.

v2.84.0

12 septembre 2026
Les verrous de catégorie sont désormais modifiables
  • subs_block et « tree_block » sont modifiables. ⚠ « subs_block » s'applique aux redirections et au plan du site de toute la branche de catégories.

v2.83.0

12 septembre 2026
Tous les points de terminaison d'exportation vérifient leurs filtres
  • Les filtres inconnus sont signalés à chaque point de terminaison d'exportation par UNKNOWN_FILTER; avec ?_strict=true, l'appel est interrompu.

v2.82.0

12 septembre 2026
Le fabricant, via le nom
  • manufacturers_name et le bloc « Fabricant » de l’exportation sont résolus. Les noms inconnus ou ambigus sont rejetés, et non créés.
  • Documentation sur les données supprimées par DELETE /product – souvent, products_status = 0 est le meilleur choix.

v2.81.0

12 septembre 2026
Les prix spéciaux et les champs supplémentaires peuvent être renvoyés
  • special est accepté sous forme de liste ou d’objet unique, slp_value en tant que nom d’étiquette.
  • extra_fields Apparaît sous forme de liste vide même en l'absence d'entrées.

v2.80.0

12 septembre 2026
Renvoyer sans perte de données
  • Corrigé : les affectations de catégories dans le formulaire d’exportation déplaçaient les produits vers la catégorie 1.
  • Les listes d'images sont d'abord vérifiées, puis enregistrées ; une image principale reste l'image principale.

v2.79.0

12 septembre 2026
Mise à jour partielle des catégories
  • Un «PUT » de catégorie n’a plus besoin du bloc de langue.
  • categories_mode: "append" Ajout d'affectations au produit ; la synchronisation complète signale les affectations supprimées via CATEGORY_ASSIGNMENTS_REPLACED.

v2.78.0

12 septembre 2026
Attribution d'un ticket à un client via PUT
  • ticket_customers_orders_id, ticket_customers_id, ticket_customers_name et ticket_customers_email sont enregistrées dans la table « PUT ». L'adresse e-mail ne peut pas être laissée vide.

v2.77.0

12 septembre 2026
Tout ou rien lors de l'importation
  • ?_strict=true Rejette complètement les produits, catégories, clients et commandes comportant des champs inconnus (400 UNKNOWN_FIELD) avant que quoi que ce soit ne soit enregistré.

v2.76.0

12 septembre 2026
Accéder aux produits via leur ID
  • Il suffit d'un PUT avec products_id. Les références d'articles utilisées plusieurs fois sont rejetées au lieu de correspondre à un article quelconque.

v2.75.0

12 septembre 2026
Filtres de produits précis
  • Nouveau : products_model et products_ean comme filtres exacts, products_id comme filtre ; manufacturers_id fonctionne désormais.
  • Si un identifiant unique dans un chemin pluriel renvoie plusieurs enregistrements, cela est signalé par RANGE_START_NOT_SINGLE_RECORD.

v2.74.0

12 septembre 2026
Tickets : pas d’envoi en cas de pièce jointe manquante
  • Si une pièce jointe est rejetée, aucun e-mail n’est envoyé au client ; le commentaire reste enregistré.
  • Nouveau champ de réponse « outcome » (ok, partial, failed) comme critère de réussite fiable.

v2.73.0

12 septembre 2026
Chiffres dans le JSON sans perte silencieuse de données
  • Si la reconnaissance des nombres convertit des valeurs (par exemple, des zéros non significatifs), cela est signalé par « NUMERIC_CHECK_APPLIED ». « ?numeric_check=false » renvoie ces valeurs telles quelles sous forme de texte.

v2.72.0

12 septembre 2026
Récupération de documents sans effet secondaire
  • Corrigé : la récupération d’une correction de facture via order_document pouvait générer un numéro de correction. En l’absence de correction existante, le point de terminaison répond désormais avec 409.
  • Les champs non renseignés d’une commandePUT renvoient FIELD_IGNORED_ON_UPDATE. Le mode de paiement, l’adresse de facturation et l’adresse de livraison peuvent être modifiés via PUT.

v2.71.0

12 septembre 2026
Lecture et écriture complètes des caractéristiques
  • ⚠ Les affectations de caractéristiques existantes sont mises à jour au lieu d’être ignorées ; les champs non envoyés restent inchangés.
  • options_replace Comparaison par différence : les écrans d’options, le facteur de prix de base et le prix d’achat ne sont plus perdus. La commande _action: "delete" supprime une attribution unique.
  • Les caractéristiques nouvellement créées sont signalées par « OPTION_CREATED » ; « options_strict_names » rejette quant à lui les noms inconnus.

v2.70.0

12 septembre 2026
La suppression nécessite désormais la méthode DELETE
  • ⚠ Veuillez vérifier votre connexion. Les points de terminaison sous Delete/JSON/ n’acceptent désormais plus que la méthode HTTP DELETE. Toute autre méthode entraîne une réponse de l’interface avec 405 METHOD_NOT_ALLOWED et le champ d’en-tête Allow: DELETE – et ce, avant que quoi que ce soit ne se produise.
  • Pourquoi cela était-il nécessaire ? Jusqu’à présent, l’interface ne vérifiait pas du tout la méthode à ce stade. Un simple appel de l’adresse dans un navigateur, un aperçu de lien ou un robot de moteur de recherche pouvait ainsi supprimer un enregistrement. Il suffisait qu’un jeton d’accès apparaisse une seule fois dans une adresse.
  • Conséquences pratiques : probablement aucune. Nous avons analysé les journaux d'accès avant la mise à jour : toutes les requêtes de suppression observées utilisaient déjà DELETE. En revanche, si votre programme utilise GET ou POST, veuillez le mettre à jour.
Les messages d’erreur sont désormais exploitables
  • Les adresses inconnues, les plages de numéros non valides et les points de terminaison inexistants renvoient désormais une réponse au format JSON accompagnée du code d'état HTTP approprié (404, 400, 501) au lieu d'une simple ligne de texte. Auparavant, le serveur renvoyait le code 200 selon le mode de fonctionnement de l’environnement PHP – un traitement des erreurs analysant le code d’état considérait donc l’appel comme ayant abouti.
  • Les objets d'erreur suivent la structure habituelle : error.code (NOT_FOUND, INVALID_RANGE, NOT_IMPLEMENTED) et error.message.

v2.69.0

7 septembre 2026
Les destinataires en copie (CC/BCC) peuvent désormais écrire
  • Nouveau champ « receivers » sur POST/PUT /ticket(s): { mode, cc, bcc }. Jusqu’à présent, les destinataires étaient en lecture seule – leur gestion s’effectuait exclusivement dans l’interface de la boutique.
  • Le mode « add » (par défaut) ajoute des destinataires, « replace » remplace uniquement les listes fournies, tandis que « remove » supprime des adresses individuelles. Les adresses sont vérifiées comme dans le backend ; une liste ne contenant que des adresses non valides laisse la liste inchangée – une faute de frappe ne doit pas vider la liste des destinataires.
  • L'opération s'effectue avant l'ajout d'un commentaire et l'envoi de l'e-mail issus de la même requête : « Compléter l'adresse et répondre » s'effectue ainsi en une seule étape.

v2.68.0

31 août 2026
Catégorie principale par produit
  • Nouveau champ « main_category_id » dans l’entité produit. Il détermine laquelle, parmi les différentes attributions de catégorie, fournit le chemin de catégorie dans l’adresse, l’adresse canonique, l’entrée dans le plan du site et l’indication de catégorie dans les flux du portail de prix.
  • ⚠ La sémantique d’importation s’écarte délibérément de categories: si le champ est absent, le stock reste inchangé. Sinon, tout programme existant qui met à jour les produits supprimerait la catégorie principale lors de sa première exécution. La valeur 0 annule cette règle.
  • Une catégorie qui n’est pas du tout attribuée au produit est rejetée et signalée – une importation ne doit pas générer d’attribution vide.

v2.67.0

26 août 2026
Le type de garantie peut désormais être importé
  • Nouveau champ « warranty_type » dans l’importation de produits. Les valeurs autorisées sont « physical » et « digital » ; l’orthographe est corrigée. La sémantique habituelle de « array_key_exists » s’applique : si la clé est absente, la colonne reste inchangée ; une chaîne vide la vide.
  • L’exportation a toujours fourni ce champ – seule l’importation ne le reconnaissait pas. Un cycle complet « exporter, modifier, réécrire » était donc impossible. La version 2.63.0 avait comblé cette lacune pour les champs de stock.
  • ⚠ Une valeur invalide est rejetée, elle n’est pas corrigée. Vous recevez un avertissement dans warnings[], la valeur existante est conservée. C’est intentionnel : ce champ détermine en partie si la boutique traite un article comme un produit physique ou comme un contenu numérique – et donc les informations obligatoires relatives à la garantie.
Sans contrat API, mais corrigé dans la même opération
  • Importation CSV : warranty_period est désormais vérifié par rapport aux valeurs autorisées. Jusqu’à présent, un texte libre était simplement converti en minuscules puis enregistré – modifié, mais tout aussi inutilisable. Il en va de même pour une garantie fabricant non valide, qui était auparavant discrètement effacée, supprimant ainsi une information correctement renseignée.
  • Importation de produits au format XML : prend en charge pour la première fois les six champs relatifs à la garantie légale et à la garantie commerciale. Si votre flux ne les fournit pas, ils restent inchangés – un flux purement consacré aux stocks ou aux prix n’y change rien.

v2.66.1

25 août 2026
Les rendez-vous supprimés disparaissent de l’exportation des tickets
  • L’exportation des tickets continuait de fournir des rendez-vous supprimés de manière temporaire. Quiconque vérifiait une suppression via le ticket pensait qu’elle avait échoué. Le champ concerné était « linked_appointments[] » de « GET /Export/JSON/tickets ».
  • La cause était une omission, et non une faute de frappe. Ce bloc provient de la version 2.11.0 – quatre mois avant l’introduction de la suppression temporaire des rendez-vous (v2.44.0) – et n’a jamais été mis à jour avec le filtre lors de la mise à jour. La suppression temporaire laisse délibérément la ligne de lien en place (restauration et « pierre tombale » CalDAV) ; c’est pourquoi chaque lecteur doit filtrer lui-même les données. Le formulaire de ticket et le widget de rendez-vous dans le backend le faisaient depuis toujours – l’API était donc en contradiction avec la propre interface de cette même boutique.
  • ⚠ Changement de comportement sans adaptation de votre part : linked_appointments[] peut devenir plus court, et des entrées peuvent disparaître entre deux consultations, sans que rien n’ait changé au niveau du ticket. Il n’y a pas de « pierres tombales » sur cette branche.
  • Les « pierres tombales » existent toujours – et sont plus complètes : GET /Export/JSON/appointments?ticket_id={id}&include_deleted=1 fournit deleted_at et les descriptions dans toutes les langues ; pour la récupération groupée, ?include_deleted=1&last_modified=… ainsi que relationships[]. La ressource « tickets » ne reçoit délibérément pas de include_deleted: le nom serait ambigu à cet endroit, car les tickets ne connaissent pas de « soft-delete ».
  • Même cause corrigée dans le backend : huit requêtes reliaient des projets, des commandes et des tickets via des rendez-vous, sans vérifier la table des rendez-vous. Un rendez-vous supprimé continuait de créer un lien, et les liens vers les rendez-vous générés à partir de celui-ci ne menaient nulle part.

v2.66.0

24 août 2026
Blocage d’importation pour la classe d’imposition
  • Nouveau type de blocage « tax » dans « import_blocks ». Cette modification a été motivée par le prix fixe du livre : le blocage du prix à lui seul ne préserve pas un prix de vente fixe ; si le prix net reste inchangé et que la classe fiscale change lors de l’importation, le prix brutmodifie malgré tout, et c’est précisément cette valeur qui est fixe. Pour les produits à prix fixe, il faut donc toujours l’utiliser conjointement avec price.
  • Ce type s’applique de manière globale (sans référence à la langue) et est pris en compte par tous les importateurs de produits. Lors de l’exportation, il apparaît automatiquement, car « import_blocks[] » est indépendant du type.
  • Parallèlement, dans le backend : le masque de l’article comporte désormais un onglet « Gestion des marchandises » au lieu de deux onglets qui contrôlaient les mêmes verrouillages et s’effaçaient mutuellement lors de l’enregistrement.

v2.65.0

24 août 2026
Filtres côté serveur pour la liste des produits
  • Jusqu’à présent, il n’existait que ?limit et ?offset. Quiconque avait besoin d’un sous-ensemble devait récupérer le catalogue complet page par page – soit 250 requêtes pour 62 000 articles, alors que la base de données répond à cette question en une seule requête.
  • Nouveaux filtres : ?status=, ?tax_class_id=, ?categories_id=, ?ean_prefix=, ?model_prefix= et ?last_modified=. Une virgule sépare une liste d’inclusion (100 valeurs au maximum) ; plusieurs filtres sont combinés par un « ET ». Exemple : ?ean_prefix=978,979,977&tax_class_id=0,1&status=1 permet de trouver tous les articles disponibles à la vente dotés d’un code EAN « livre » qui ne bénéficient pas du taux réduit.
  • Absence délibérée de l’opérateur « différent de »: l’APIne le reconnaît pour aucune entité. « Tout sauf la classe fiscale 2 » s’écrit sous forme de liste d’inclusion des autres classes ; cela reste indexable, au lieu d’introduire un deuxième langage de requête.
  • stats.total indique désormais le nombre de résultats. Auparavant, ce champ affichait toujours le nombre total de produits, quelle que soit la requête – stats.has_more était donc incorrect.
  • Une valeur de filtre invalide génère une erreur (HTTP 400), et non un avertissement. Si le filtre était discrètement ignoré, le catalogue non filtré serait renvoyé – une recherche d’enregistrements erronés afficherait alors « rien trouvé ». Les filtres appliqués à une ressource unique ou à une plage d’identifiants sont rejetés pour la même raison.
  • include_inactive_products Sans objet. Ce nom faisait partie de la liste des produits d’une catégorie, n’a jamais été pris en compte lors de l’exportation des produits et a été remplacé par ?status=. Il génère désormais un avertissement au lieu d’une inefficacité silencieuse.
  • Schéma : nouvel index sur products_last_modified (programme d’installation et auto-réparation ; pour les très grands catalogues, c’est le HealthCheck qui le propose à la place) – sans lui, le filtre delta effectuerait un parcours complet de la table.

v2.64.0

24 août 2026
Les adresses de livraison peuvent rester vides
  • Les colonnes d’adresse d’une commande peuvent désormais contenir la valeur NULL (rue, ville et code postal pour les adresses client, de livraison et de facturation). Les importations depuis les places de marché en deux phases créent les commandes à retirer avant même le paiement – l’adresse n’est alors pas encore disponible et est ajoutée lors de la deuxième récupération.
  • L’exportation renvoie « null » pour ces commandes au lieu d’une chaîne vide – « null » signifie « l’adresse n’est pas encore disponible », tandis qu’une chaîne vide signifie « vide ». La raison sociale, le complément d’adresse et la région ont toujours pu accepter la valeur NULL.
  • Correction : les indicateurs de divergence entre l’adresse de facturation et l’adresse de livraison effectuent désormais une comparaison qui tolère la valeur NULL. Auparavant, un champ vide les faisait passer à tort à « divergent ».

v2.63.0

17 août 2026
Stocks consultables, champs de stock de l’entrepôt principal modifiables
  • L’exportation fournit les données « storages[] » : l’exportation des produits inclut désormais les stocks – pour chaque ligne de stock : storages_id, products_quantity, products_safe_quantity, products_reorder_level, products_storage_text et options_id. Jusqu’à la v2.62.0, l’exportation JSON ne les fournissait pas du tout: les stocks étaient modifiables via l’API, mais non lisibles, ce qui rendait tout aller-retour impossible. L'ensemble des champs correspond exactement à l'importation ; les données de stock exportées peuvent donc être réimportées telles quelles.
  • Si le système de stock étendu est désactivé, la clé est totalement absente (et non sous forme de tableau vide) – cela permet à un client de distinguer « fonction désactivée » de « aucune ligne de stock disponible ». Toutes les lignes de stock du produit sont affichées, y compris celles correspondant à des stocks inactifs.
  • Entrepôt principal configurable via l’importation : les champs « products_reorder_level » et « products_safe_quantity » sont désormais autorisés au niveau supérieur du produit et écrivent dans l’entrepôt principal (la table « products »). L’exportation a toujours fourni ces deux colonnes, mais l’importation les rejetait comme des champs inconnus – il était donc impossible de réimporter un produit exporté sans perte de données.
  • À ne pas confondre : les champs du même nom dans storages[] appartiennent à un entrepôt supplémentaire. storages_id: 1 correspond déjà au premier entrepôt supplémentaire – l’entrepôt principal ne figure pas dans la liste des entrepôts.
  • Correction products_quantity: le stock n’est plus arrondi aux nombres entiers lors de l’importation. La colonne autorise les décimales, et lorsque l’option « Quantités fractionnaires dans le panier » est activée, celles-ci sont techniquement souhaitées (articles vendus au mètre, articles vendus au poids) – jusqu’à présent, 0.5 devenait 0, ce qui signifiait que l’article était « en rupture de stock ». Changement visible pour les interfaces qui transmettent des décimales : la valeur est désormais prise en compte, au lieu de disparaître sans laisser de trace.
  • Inchangé : storages[] reste une mise à jour partielle sans synchronisation complète (v2.45.0) ; les lignes de stock non transmises restent inchangées. L’import CSV/XML et l’enregistrement dans le backend continuent d’écrire la ligne de stock complète.

v2.62.0

13 août 2026
Label de garantie de l’UE (GARAN) via l’interface
  • Nouveaux champs produit : garan_label_enabled (0/1) active le label de garantie de l’UE conformément au règlement (UE) 2025/1960 – obligatoire à compter du 27 septembre 2026. Pour cela, utilisez garan_brand (marque différente de celle du catalogue) et garan_model (identifiant du modèle pour le label) ; une chaîne vide supprime la valeur correspondante. L’identifiant du modèle comporte environ 14 caractères – des valeurs plus longues empêchent l’affichage du label.
  • L’étiquette a une valeur juridique contraignante : chaque validation via l’interface est consignée. C’est l’exploitant de la boutique qui confirme le respect des conditions préalables, et non l’API.
  • Garantie constructeur désormais exprimée en demi-années : « manufacturer_guarantee_years » est une valeur décimale. Les valeurs comportant une virgule ("2,5") sont acceptées et arrondies au demi-niveau inférieur le plus proche, jamais au niveau supérieur. Attention aux analyseurs syntaxiques stricts : l’exportation fournit désormais « "5.0" » au lieu de « "5" ».

v2.61.0

12 août 2026
Récupération des documents justificatifs d’une commande
  • Nouveau point de terminaison : GET /Export/JSON/order_document/{orders_id}?type=rg fournit le document final au format JSON avec un PDF encodé en base64. Types de documents disponibles : of (devis), ab (confirmation de commande), rg/rgqr (facture, avec ou sans partie « QR » suisse), ls (bon de livraison), st (annulation), pl (liste de colisage), prg (facture pro forma), dr (attestation de don) et so. Portée orders:read.
  • Pourquoi base64 plutôt qu’un flux binaire : le champ s’appelle « content_base64 » – exactement comme pour les pièces jointes aux tickets depuis la version 2.60.0. Cela permet de joindre directement un justificatif à un ticket sans passer par un fichier intermédiaire.
  • C’est exactement le justificatif du backend qui est généré : le même moteur de rendu que pour les pièces jointes aux e-mails est utilisé, dans un processus distinct et sans session. Si un fichier de facture est enregistré pour une commande, celui-ci est transmis.
  • Cas d’erreur évidents : commande inconnue → 404, justificatif de facture sans date de facturation → 409, type de justificatif non autorisé → 400 – dans chaque cas sous forme de JSON propre.
  • Non inclus : les types eiv_*(XRechnung, ZUGFeRD) sont délibérément exclus – ils génèrent du XML au lieu d’un PDF.

v2.60.0

11 août 2026
Les pièces jointes aux tickets sont désormais modifiables
  • Nouveau champ « attachments[] » : les URL POST et PUT /Import/JSON/tickets acceptent désormais des fichiers – pour chaque entrée, un name (nom de fichier, extension comprise) et un content_base64 (contenu encodé en Base64).
  • Comportement antérieur : les pièces jointes étaient uniquement consultables (liste et téléchargement depuis la v2.9.0) ; elles ne pouvaient être ajoutées que via le formulaire du backend. Un ticket créé via l’API restait donc sans pièce jointe – un PDF, un fichier .eml ou une capture d’écran devaient être fournis manuellement par la suite.
  • Les pièces jointes sont associées à une entrée de l’historique, et non au ticket : sans ticket_comments dans la même requête, aucune entrée à laquelle le fichier pourrait être associé n’est créée. Il est alors rejeté avec un message d’erreur au lieu d’être simplement ignoré.
  • Mêmes règles que dans le backend : liste blanche d’extensions identique, même convention de nommage et déduplication par hachage pour éviter les doublons. Le nom de fichier effectivement attribué figure, pour chaque enregistrement, dans la réponse sous attachments. La limite maximale par fichier correspond au point de terminaison /media(par défaut 10 Mo).
  • Tolérance aux erreurs : une extension non autorisée, un Base64 non valide ou un dépassement de la taille limite génèrent une erreur par fichier – la mise à jour du ticket elle-même reste réussie. En cas de réponse publique avec notification, les fichiers sont envoyés via l'e-mail du client.
  • Intégrations existantes : elles restent opérationnelles sans modification – le champ est facultatif, l’extension est purement complémentaire. Portée tickets:write.
Corrections apportées à la documentation
  • Correction des champs de commentaire : lors de la création d’un ticket, la page Endpoint mentionnait les champs initial_comment et initial_comment_admin_id – ces deux champs n’existent pas dans l’interface. Les champs corrects sont ticket_comments (texte du commentaire) et admin_id. De même, lors de la mise à jour, ticket_comments est un texte, et non un tableau d’objets. Les utilisateurs qui se sont fiés à l’ancienne description n’ont pas reçu de commentaire – et ne peuvent donc pas non plus ajouter de pièces jointes, car rien ne peut être joint sans entrée dans l’historique.
  • Réponses publiques : la mention « Les réponses directes aux clients ne sont pas possibles via l’API » était obsolète depuis la version 2.25.0 et a été remplacée. Les indicateurs is_public_reply, notify_customer et append_signature sont désormais décrits dans le tableau des champs.
  • Aucune modification du code : ces deux points concernent exclusivement la documentation ; le comportement de l’interface reste inchangé.

v2.59.0

6 août 2026
Extensions internes
  • Aucune modification des points de terminaison documentés : cette version étend exclusivement une interface de support interne de XONIC. Les opérations d’exportation, d’importation et de suppression (DELETE) fonctionnent comme auparavant.
  • Intégrations existantes : elles restent opérationnelles sans modification – le numéro de version est simplement incrémenté.

v2.58.0

6 août 2026
Groupes de caractéristiques combinés dans l’exportation de produits
  • Nouveau champ « option_groups[] » : les caractéristiques associées à un groupe de caractéristiques dans la boutique (généralement « couleur + taille ») sont désormais fournies par l’exportation de produits – y compris les éléments du groupe dans l’ordre d’affichage et, pour chaque combinaison, la référence, l’EAN, la quantité, le prix et le tri correspondants.
  • Comportement antérieur : les caractéristiques groupées étaient totalement absentes de l’exportation – sans champ vide ni mention particulière. Seules les caractéristiques non groupées (options{}) étaient exportées.
  • Pourquoi deux champs ? Dans le cas d’un groupe de caractéristiques, la référence et l’EAN font partie de la combinaison de valeurs (« noir / L » = un EAN), tandis que dans le cas d’une caractéristique unique, ils correspondent à une valeur unique. options{} reste donc inchangé – il s’agit d’une extension purement additive.
  • Inchangé : les exportateurs XML et CSV continuent de n'exporter que des caractéristiques non regroupées. L'importation continue d'attendre le format plat options[].

v2.57.1

22 juillet 2026
Correction d’un bug : prix spécifiques au client dans l’importation de produits au format XML
  • Importation de produits au format XML : le bloc « customers » situé dans groups (prix spécifiques par client et par produit) était ignoré lors de la lecture et n’était jamais enregistré dans la base de données ; les entrées sont désormais importées correctement. L’affectation des clients s’effectue via id (ID client de la boutique) ou external (numéro de client WaWi) ; les numéros de client inconnus sont ignorés.
  • Règles claires pour les entrées incomplètes : price 0 sans prix échelonnés ne crée pas de ligne (Supprimer = omettre l’entrée – l’importation reflète intégralement la liste des prix clients par produit) ; les quantity_blocks/min_quantity manquants sont préremplis avec la valeur 1, comme lors de l’importation REST.

v2.57.0

18 juillet 2026
Remises clients et prix personnalisés
  • Clients : nouveau champ « discounts[] » – gérer les remises clients (le champ « Remises » de la gestion des clients) via l’API. Sémantique « replace-on-present » : si le champ contient des entrées, les remises existantes du client sont entièrement remplacées ; un « [] » vide supprime toutes les remises ; si le champ est vide, les remises restent inchangées. L’exportation « Customers » fournit désormais « discounts » (aller-retour).
  • Importation des produits : nouveau champ customers_prices[] – prix personnalisés par client, y compris les prix échelonnés, sous forme de « Partial Upsert » (seules les colonnes transmises sont écrites). _action: "delete" supprime l’entrée d’un client, customers_prices_replace: true bascule en mode « miroir complet » ; le client est identifié via customers_id ou customers_id_extern (numéro de client WaWi).
  • Importation des clients : customers_id_extern et customers_group_id sont désormais accessibles en écriture ; PUT permet également d’adresser le client sans e-mail via customers_id ou customers_id_extern (gestion des remises et des données de base uniquement).

v2.56.0

16 juillet 2026
Extensions internes
  • Aucune modification des points de terminaison documentés : cette version étend exclusivement une interface de support interne de XONIC. Les opérations d’exportation, d’importation et de suppression (DELETE) fonctionnent comme auparavant.
  • Intégrations existantes : elles restent opérationnelles sans modification – le numéro de version est simplement mis à jour.

v2.55.0

15 juillet 2026
Extensions internes
  • Aucune modification des points de terminaison documentés : cette version étend exclusivement une interface de support interne de XONIC. Les fonctions d'exportation, d'importation et de suppression fonctionnent comme auparavant.
  • Intégrations existantes : elles restent fonctionnelles sans modification – seul le numéro de version augmente.

v2.54.0

14 juillet 2026

Commandes : les champs de date – notamment la date de prestation – peuvent désormais être définis pour chaque poste. Cela est nécessaire pour les factures groupées dans lesquelles chaque lot de travaux comporte sa propre date de prestation (les documents l’indiquent alors sous la ligne d’article correspondante plutôt qu’une seule fois dans l’en-tête du document). De plus, la fonction « PUT /orders » (Ajouter des lignes ) avec l’option « products_mode: "append" » (Ajouter des lignes de commande ) permet d’ajouter des lignes à une commande existante; les totaux sont ensuite recalculés. Les commandes qui sont déjà considérées comme des factures – parce qu’un numéro de facture leur a été attribué ou que la série de numéros individuelle est désactivée – sont refusées avec le message « ORDER_ALREADY_INVOICED » : une facture émise ne peut pas être modifiée a posteriori. Les mises à jour de statut, de suivi et de date ne sont pas affectées par cette mesure.

v2.53.0

14 juillet 2026

Commandes : le groupe de dates de l’éditeur de commande peut désormais être défini via l’API – service_date (date de prestation), estimated_service_date, shipping_date, estimated_shipping_date, invoice_date (date de facturation), invoice_payment_term_date (délai de paiement) ainsi que la date souhaitée desired_delivery_date sous forme de texte libre. S'applique à la création d'une nouvelle entrée (POST) et à la mise à jour (PUT) ; les dates sont analysées avec une certaine tolérance.

v2.52.0

14 juillet 2026

Importation de produits : grâce à « import_blocks », il est possible de protéger de manière ciblée certains champs d’un produit existant contre l’importateur XML – par exemple lorsque la description en allemand provient du système de gestion des stocks, mais que la description en anglais est gérée dans la boutique. Il s’agit de l’équivalent programmatique de l’onglet du backend « xoPort Interface de données (XML) ». Le nom et la description (par langue) ainsi que sept catégories de prix peuvent être protégés.

v2.51.0

11 juillet 2026

Importation de produits : extra_fields accepte désormais les champs supplémentaires soit via l’ID du champ, soit via le nom du champ – sous forme d’objet ou de liste, y compris la structure fournie par l’exportation JSON (aller-retour export/import). Auparavant, seule la liste avec products_extra_fields_id était prise en compte ; les orthographes divergentes étaient rejetées sans avertissement. Les champs supplémentaires non identifiables génèrent désormais un avertissement « EXTRA_FIELD », et un champ qui se trouve par erreur au niveau supérieur au lieu d’être dans « extra_fields » est mentionné dans l’avertissement avec l’ID de champ correspondant. Cela concerne notamment les champs Google Shopping.

v2.50.0

30 juin 2026

Optimisations internes et améliorations de la stabilité de l'API xoPort.

v2.49.0

25 juin 2026

DELETE /customer_group/{id} (Portée customer_groups:delete) : suppression d'un groupe de clients avec deux mécanismes de protection stricts – le groupe 0 (« clients finaux ») ne peut pas être supprimé (403), et un groupe auquel des clients sont encore affectés est refusé (409, il faut d'abord regrouper les clients). Nettoie toutes les données associées (remises, offres spéciales, tarifs de groupe, entrées de filtrage).

v2.48.0

25 juin 2026

Nouvelle entité customer_groups (exportation + importation) : énumérer et gérer les groupes de clients via l’API – y compris les restricted_categories_ids parsemées (liste noire des catégories du groupe). POST/PUT avec validation d’énumération et durcissement des ID ; POST nécessite une customers_group_id explicite (pas d’AUTO_INCREMENT). Deux nouvelles portées : customer_groups:read + customer_groups:write.

v2.47.0

25 juin 2026

Liste noire des catégories et des groupes de clients : restricted_customer_groups désormais également disponible pour les catégories (auparavant uniquement pour les produits). L’importation synchronise customers_groups.restricted_categories, l’exportation renvoie ce champ. Récursif: si l’on bloque une catégorie parente, toutes les sous-catégories actives sont également bloquées.

v2.46.0

20 juin 2026

Téléchargement de médias entity_type=static: nouveau mode « wildcard » / « liste noire ». Avec XOPORT_MEDIA_STATIC_FOLDERS = '*', tous les sous-dossiers de images/ sont accessibles en écriture, à l’exception de ceux gérés par le système de gestion des images (source/, thumbnail/). La liste d’autorisation stricte reste la valeur par défaut ; ce mode est optionnel. Renforcement supplémentaire : jeu de caractères strict pour les noms de dossiers, confinement des chemins d’accès sous images/ et protection contre l’écrasement (fichier existant uniquement avec overwrite:true). Nouveaux codes d’erreur PROTECTED_TARGET_FOLDER (403) et FILE_EXISTS (409).

v2.45.0

19 juin 2026

Importation de produits storages[]: mise à jour partielle. Les stocks par entrepôt ne sont désormais enregistrés que pour les champs effectivement transmis (INSERT … ON DUPLICATE KEY UPDATE au lieu de REPLACE). Une charge utile partielle telle que {"storages_id":1,"products_reorder_level":50} ne modifie ainsi que le niveau de stock déclaré et ne remet plus à 0 les autres colonnes de stock. Les charges utiles complètes restent rétrocompatibles.

v2.44.0

18 juin 2026
API Appointments : point de terminaison de calendrier autonome
  • Nouvelle ressource de premier niveau appointments avec CRUD complet : GET /appointments, POST/PUT /appointments ainsi que DELETE /appointment/{id} (suppression temporaire → CalDAV-Tombstone).
  • Les rendez-vous sont créés via la logique centrale de gestion des rendez-vous (CalDAV-UID, updated_at) et apparaissent immédiatement dans le calendrier des administrateurs responsables ainsi que dans la synchronisation CalDAV.
  • Champs, entre autres : startdate (obligatoire), enddate/deadline, allday/vacation/private/done, rappels, titre/description/lieu (multilingue), responsibilities, followers, categories et relationships (lien vers un ticket, une commande, un client ou un projet).
  • Filtres d’exportation : plage horaire, responsabilité, lien (par ex. ?ticket_id=) ainsi que ?last_modified= pour la synchronisation delta. PUT contient les champs non transmis.
  • Trois nouvelles portées : appointments:read, appointments:write, appointments:delete.

v2.43.0

18 juin 2026
API des tickets : création de rendez-vous associés
  • POST/PUT /tickets accepte désormais le champ facultatif linked_appointments — pour chaque ticket, il est possible de créer directement des rendez-vous.
  • Chaque entrée génère un rendez-vous dans le calendrier et le lie au ticket. Responsables = les administrateurs affectés au ticket, Titre par défaut = objet du ticket.
  • Équivalent du champ d’exportation existant « linked_appointments » ; portée requise : « tickets:write ».

v2.42.0

15 juin 2026
Types d’entités de slider et slider d’actualités (à partir de Shop 4.8)
  • À partir de XONIC 4.8 (toutes les versions postérieures à la version 4.7.15), la table slider utilise la paire de colonnes polymorphes entity_type (category / content / news) + entity_id au lieu de categories_id + content_id.
  • La charge utile du slider (exportation et importation) s'effectue désormais via entity_type + entity_id. Les clients qui envoient encore categories_id/content_id doivent effectuer la mise à jour.
  • Nouveau type news: les diapositives peuvent désormais également être associées à des articles d'actualité. Slider de la page d'accueil = entity_type=content, entity_id=0.
  • Les filtres d'exportation ?categories_id= / ?content_id= sont conservés et sont mappés en interne vers le type d'entité. Les boutiques existantes sont migrées automatiquement via la fonction « Self-Heal ».

v2.41.0

14 juin 2026
API multimédia : pièces jointes aux projets et aux tâches
  • POST /media Avec entity_type=project (ou task), vous pouvez joindre directement des documents PDF à un projet xoCRM ou à une tâche.
  • Le fichier est enregistré dans l’espace de stockage interne et sécurisé du projet et apparaît immédiatement dans l’onglet « Fichiers » — idéal pour les documents internes tels que les plans de projet.
  • Champs obligatoires : entity_id (ID du projet ou de la tâche, vérifié), file_name et une source (file_url, file_base64 ou téléchargement multipart).
  • Actuellement, les fichiers PDF (application/pdf) sont pris en charge ; portée requise : media:write.

v2.40.0

11 juin 2026
API Projects : enregistrement d’un statut sans changement de statut
  • PUT /projects ou /project_tasks avec status_comment permet désormais d’ajouter une entrée dans l’historique des statuts même sans changement de statut — idéal pour les comptes-rendus de réunion et les notes de travail.
  • Les entrées de tâches comportent l’ progress_percent — la barre de progression apparaît dans l’historique.

v2.39.2

11 juin 2026
Correction d’un bug : frais d’options ponctuels dans l’interface utilisateur
  • Lors de l’importation d’options avec présélection, l’ pre_option est désormais également défini dans le masque d’options — auparavant, la ligne « plus » correspondant aux frais d’option uniques n’apparaissait pas sur la page du produit. pre_option est également autorisé en tant que champ explicite dans la charge utile.
  • Correction au niveau du noyau : le prix de l’option était perdu lorsque le tableau des détails de l’option était entièrement vide.

v2.39.1

11 juin 2026
Correction d’un bug : caches des produits après l’importation
  • Après chaque importation de produits, les caches des produits sont mis à jour (présélection des options, étiquettes de prix) — comme lors d’une sauvegarde dans le backend.
  • Auparavant, les majorations de prix liées aux caractéristiques et les modifications de prix définies via l’API n’étaient visibles dans le front-end qu’après une nouvelle sauvegarde manuelle.

v2.39.0

11 juin 2026
Importation de produits : caractéristiques et options (options[])
  • Les attributs de produit peuvent désormais être créés via POST/PUT /Import/JSON/products: pour chaque entrée, option_id ou option_name + value_id ou value_name — les options/valeurs manquantes sont créées automatiquement.
  • Champs de contrôle : option_type (par ex. 5 = affichage uniquement), option_sort, option_required, price (supplément), pre_select, status, model, ean, quantity, weight, image.
  • Les combinaisons déjà attribuées sont ignorées (avertissement OPTION_EXISTS_SKIPPED) ; options_replace: true reconstruit entièrement les attributs du produit.

v2.38.0

11 juin 2026
Produits : liste de blocage des groupes de clients
  • Nouveau champ « restricted_customer_groups[] » dans l’exportation et l’importation de produits : identifiants des groupes pour lesquels le produit est bloqué.
  • L’importation remplace intégralement la liste de blocage si ce champ est inclus dans la charge utile ; un tableau vide supprime tous les blocages.
  • Cela permet de transférer des restrictions de visibilité (par exemple, réservé à un groupe de clients spécifique) d’un produit à un autre via l’API.

v2.37.0

11 juin 2026
Importation de produits : Click2Call et blocage de l'achat direct
  • Deux nouveaux indicateurs de produit importables : click2call (bouton d’appel à la place du panier) et non_directcart (pas d’achat direct) — via POST/PUT /Import/JSON/products.
  • Comportement identique à non_cart/non_price: seuls les champs définis sont modifiés.

v2.36.0

11 juin 2026
API Projets : entrées de statut dans l'exportation
  • Les projets et les tâches fournissent désormais status_history[] avec — toutes les entrées de statut gérées dans le backend, y compris les commentaires (par exemple, les comptes-rendus de réunion).
  • Champs par entrée : status_id + status_name, date_added, comments, progress_percent, user_id + user_name.
  • Simplement une mise à jour, pas de nouvelle version — il suffit d'installer projects:read ou project_tasks:read.

v2.35.0

11 juin 2026
API Projets : projets xoCRM et tâches de projet
  • Deux nouveaux types d’entités : projects (projets xoCRM) et project_tasks (tâches de projet) — avec respectivement des fonctions d’exportation, d’importation et de suppression.
  • Points de terminaison : GET /Export/JSON/projects (unique/plage/filtre, ?include_tasks=1 avec tâches intégrées en option), POST/PUT /Import/JSON/projects, DELETE /Delete/JSON/project/{id} — de même pour project_tasks.
  • Six nouveaux champs d'application : projects:read/write/delete + project_tasks:read/write/delete.
  • Projets : multilingues descriptions[], catégories, attribution aux clients (customer_scope), chefs de projet (leader_admin_ids), liens vers les commandes/tickets (relationships[]), is_private.
  • Tâches : priorité (1-5), avancement (0-100 %), échéance, heures prévues/réelles, attribution aux responsables (assigned_admin_ids).
  • Gestion des statuts : validation par rapport à la gestion des statuts, enregistrement automatique de l’historique des statuts lors de la création et des changements de statut (status_comment, admin_id).
  • Suppression en cascade : la suppression d’un projet supprime également toutes les tâches associées ; les commandes/tickets liés sont simplement dissociés.

v2.34.0

10 juin 2026
Importation de produits : automatisation des produits de deuxième choix et nouveaux champs
  • warranty_period: la durée de garantie est configurable ; une chaîne vide "" remplace la valeur par défaut 24m.
  • products_xoport: le champ « marqueur » (par ex. googleblacklist) peut désormais être importé.
  • images[]: Attribution d’images de produit supplémentaires par nom de fichier (remplace la galerie existante), y compris les textes alternatifs multilingues ; format tableau ou objet.
  • storages[]: Définir les stocks par entrepôt (gestion multi-entrepôts) — uniquement si le système multi-entrepôts est activé ; le stock total products_quantity reste distinct.
  • downloads[]: Créer des téléchargements de produits (par ex. PDF) ; d_src renvoie vers un fichier situé dans files/.
  • Téléchargement de médias : POST /media avec entity_type=download télécharge des fichiers PDF/documents vers files/.

v2.33.0

9 juin 2026
Auteurs d'actualités : point de terminaison newsdesk_authors & author_id
  • Nouveau point de terminaison /newsdesk_authors: exporter les auteurs d’actualités en tant que ressource distincte (GET /newsdesk_authors, GET /newsdesk_author/{id}) et les créer (POST/PUT /newsdesk_authors). Portée news:read/news:write.
  • Champs : neutres sur le plan linguistique authors_name, authors_image, authors_email, authors_url, authors_company (remplacement du nom de l'entreprise pour les auteurs externes), authors_since_year, authors_status, sort_order; par langue authors_jobtitle et authors_bio.
  • Lien author_id: la fonction d'importation/exportation d'actualités (newsdesks) inclut désormais author_id — les articles peuvent être directement associés à un auteur.

v2.32.0

7 juin 2026
Importation des commandes : parité de paiement pour la ligne fiscale et les informations d’adresse supplémentaires
  • Ligne fiscale par taux : ot_tax est désormais affiché pour chaque taux avec un libellé correspondant exactement au taux dans le format du frontend — « TVA 19 % en sus » en mode net ou « TVA 19 % incluse » en mode brut (uniquement si MODULE_ORDER_TOTAL_PREFIX=true) — à la place de l’ancienne ligne collective statique « TVA : ». Les montants restent inchangés.
  • Nouveau champ d’adresse additional_address: désormais inclus dans les champs d’adresse autorisés — le complément d’adresse est repris après customers_additional_address, delivery_additional_address et billing_additional_address (plus d’avertissement « UNKNOWN_FIELD »).

v2.31.0

7 juin 2026
Importation des commandes recalc: remises par catégorie et par client incluses dans le prix
  • Le mode « recalc » applique désormais au prix des lignes de commande non seulement les prix de groupe et les offres spéciales, mais aussi les remises par catégorie et par client (customers_discount + customers_groups_discount, y compris l’héritage des sous-catégories — même logique que sur l’interface publique).
  • Le prix normal fait toujours l’objet d’ une remise, tandis que l’ offre spéciale ne s’applique qu’en cas de « d_special=1 »; c’est le moins cher des deux prix effectifs qui prévaut. Ainsi, la commande transférée affiche exactement le prix que le client paie lors du paiement.
  • Effort maximal : en cas de problème, l’avertissement « CATEGORY_DISCOUNT_UNAVAILABLE » s’affiche et le calcul s’effectue sans remise. Hypothèse : un client par requête. Les commandes d’invités/de la place de marché (sans « customers_id ») restent inchangées.

v2.30.0

7 juin 2026
Importation des commandes : parité dropshipping lors du paiement
  • Caractéristiques « affichage uniquement » : apply_default_attributes prend désormais également en charge les caractéristiques d’affichage avec présélection (type d’option 5, par exemple « Modèle »/« Indice de protection »), y compris le supplément signé — exactement comme elles apparaissent lors du paiement. Seules les caractéristiques internes masquées (type 6) restent exclues.
  • Prix d’achat et GTIN : en mode « recalc », le prix d’achat (products_ek_price issu de products_cost) et le GTIN/EAN (products_ean) sont ajoutés à la ligne de commande, à condition que l’appelant ne fournisse aucune information.
  • Nouvel indicateur compute_shipping (niveau supérieur, valeur par défaut false) : en l’absence d’une totals.shipping explicite, le mode de livraison le moins cher est calculé « en mode headless » via la pile de gestion des livraisons du front-end (shipping::cheapest()) pour l’adresse de livraison, puis enregistré sous la forme ot_shipping (taux d’imposition = taux d’imposition dominant du produit). Best-effort : les erreurs ne génèrent pas d’exception, mais renvoient l’avertissement SHIPPING_AUTO_FAILED ou SHIPPING_AUTO_EMPTY — la commande est conservée.
  • Cas d’utilisation : transfert en dropshipping (par ex. SPV → SST), dans lequel la commande suivante doit comporter des caractéristiques, des codes EK/GTIN et des frais de port exactement identiques à ceux d’une commande manuelle passée sur la boutique.

v2.29.0

7 juin 2026
Importation des commandes : envoi facultatif de la confirmation de commande
  • Nouvel indicateur « send_confirmation_email » (niveau supérieur, true) : une fois la commande créée avec succès, la confirmation de commande standard est envoyée au client — exactement comme lors d’un paiement normal ou via les importateurs de marketplace, y compris les destinataires en copie issus de SEND_EXTRA_ORDER_EMAILS_TO.
  • Destinataires et langue : e-mail issu de la commande créée (avec validation), langue issue de la charge utile ou de la commande.
  • Retour d’information : le résultat est indiqué sous la forme « confirmation_email_sent » (vrai/faux) dans l’enregistrement correspondant de la réponse. Les erreurs d’e-mail n’interrompent pas l’importation.
  • Valeur par défaut inchangée : sans ce drapeau, aucun e-mail n’est envoyé (entièrement rétrocompatible).

v2.28.0

7 juin 2026
Importation des commandes : remplissage automatique des données client, résolution des SKU et attributs par défaut automatiques
  • Adresse de facturation à partir du numéro de client : en cas de « customers_id > 0 » et d’« billing » incomplet ou manquant, l’adresse de facturation par défaut du client (fiche client + carnet d’adresses) est reprise — les champs explicitement fournis prévalent. « delivery » reste indépendant pour les adresses de livraison différentes.
  • Résolution des SKU : les articles peuvent être fournis uniquement via products_model (= SKU) + products_quantity; products_id et products_name sont complétés à partir de la boutique. SKU inconnu → avertissement PRODUCT_MODEL_NOT_FOUND.
  • Attributs par défaut automatiques : apply_default_attributes: true reprend dans la commande, pour chaque article ne disposant pas d’attributs propres, les valeurs d’options présélectionnées dans la boutique, y compris le supplément.
  • Correction du calcul des quantités : en mode « recalc », le prix unitaire net est désormais enregistré correctement (auparavant, il était doublé dans le sous-total lorsque la quantité était supérieure à 1).

v2.27.1

2 juin 2026
Tickets : réponse publique via l’API identique à celle de l’outil de gestion
  • Profil de l’auteur : dans « is_public_reply=true », l’entrée d’historique apparaît sous le profil du ticket de l’administrateur intervenant (source : admin.ticket_settings) au lieu d’apparaître sous le prénom et le nom d’utilisateur. Ordre : facultatif ticket_admin_id → admin.ticket_settings → TICKET_DEFAULT_ADMIN_ID → nom d’utilisateur.
  • « Réponse intégrée » : l’indicateur ticket_customer_notified_embedded est activé en cas de réponse publique avec envoi d’e-mail — le texte de la réponse est intégré à l’e-mail du client.
  • CC/BCC : les destinataires CC/BCC du ticket sont enregistrés dans l’historique (badge visible) et inclus dans l’e-mail.
  • Vérification de l’envoi d’e-mail : la valeur renvoyée par l’envoi d’e-mail est analysée — un échec d’envoi génère désormais une erreur au lieu d’un retour silencieux success.

v2.26.0

1er juin 2026
Exportation des commandes : pagination au niveau SQL (correction de mémoire)
  • Problème : jusqu’à présent, GET /Export/JSON/orders chargeait l’intégralité de l’enregistrement de commande (y compris les lignes, les totaux et le suivi) en mémoire, puis ne le découpait qu’ensuite via ?limit/?offset — sur les boutiques enregistrant un grand nombre de commandes, cela entraînait une erreur fatale PHP « Allowed memory size exhausted », même avec ?limit=1.
  • Solution : LIMIT/OFFSET sont désormais — à l’instar du point de terminaison /products — directement appliqués à la requête orders_id. Seule la page demandée est chargée (par défaut 50, max. 250 via XOPORT_API_MAX_LIMIT).
  • Compatible avec les filtres : stats.total respecte les filtres actifs (?status, ?customer_id, ?date_from/to, ?since, ?products_id, …) ; la réponse contient stats.total/limit/offset/has_more.
  • Inchangé : la ressource unique /order/{id} et la plage /orders/{a}:{b} restent délibérément sans pagination (comme pour les produits).

v2.25.0

30 mai 2026
Tickets : signature de l’administrateur sur les réponses publiques
  • Signature automatique : pour is_public_reply: true, la requête PUT /Import/JSON/tickets ajoute désormais automatiquement au texte de la réponse la signature de l’administrateur enregistrée dans le backend (admin_settings.signatures.tickets), tant dans l’historique que dans l’e-mail envoyé au client, exactement comme l’outil de réponse du backend.
  • Langue : langue par défaut de la boutique ; si celle-ci n’est pas disponible, le système utilise la première signature enregistrée. Si l’administrateur n’a pas de signature, le texte reste inchangé.
  • Désactivation : le drapeau optionnel append_signature: false (strictement booléen) désactive l’ajout de la signature.
  • Important pour les clients : ne plus envoyer de signature propre dans « ticket_comments » — sinon, elle apparaîtra en double.

v2.24.0

29 mai 2026
Tickets : réponses publiques + notification client
  • Nouveauté dans le bloc de commentaires de la requête PUT /Import/JSON/tickets: deux indicateurs booléens facultatifs par élément — is_public_reply (true → l’entrée dans l’historique devient publique) et notify_customer (true → e-mail envoyé au client). Les deux ne sont effectifs qu’en mode strict === true; toutes les autres valeurs sont ignorées.
  • Comportement par défaut inchangé : sans indicateurs, le commentaire reste interne (ticket_internal_comment=1, pas d’e-mail) — rétrocompatible avec tous les clients v2.11.0+.
  • L’envoi d’e-mails utilise le même modèle $mail_ticket_update_with_content que l’outil backend (xpanel/tools-ticket-show.php), y compris les champs CC/BCC issus de ticket_additional_data.receivers et les pièces jointes de la ligne d’historique correspondante.
  • Paramètre de sécurité par défaut : is_public_reply=true sans admin_id > 0 valide revient automatiquement à « interne » + « sans e-mail » et renvoie un error. Aucune nouvelle portée n’est nécessaire (tickets:write suffit).
  • Cas d’utilisation : les agents IA ou les outils externes peuvent désormais répondre aux tickets non seulement sous forme de note interne, mais aussi en tant que véritable réponse au client — avec un indicateur d’opt-in clair, afin qu’une « publication accidentelle » soit pratiquement impossible.

v2.23.0

29 mai 2026
Correction relative à la ressource unique + cohérence de l’API
  • Correction de bug : GET /products/{id} renvoie désormais exactement un produit. Auparavant, en raison du routage des chemins au pluriel, la sémantique de plage WHERE products_id >= {id} s’appliquait — le client voyait, via .data[0], un produit aléatoire issu du résultat de l’analyse.
  • CHANGEMENT MAJEUR pour les catégories : le format de requête ?id= introduit dans la v2.1.0 pour /categories?id={id} a été supprimé. La ressource unique n’est désormais disponible dans toute l’API que sous forme de chemin d’accès (/categories/{id}, /products/{id}). Justification : une URL canonique par ressource, pas de chevauchement avec les filtres en masse (?limit/?offset/?status/?language).
  • Inchangé : la forme « range » /products/100:200 et la pagination en masse (?limit=&offset=).
  • Remarque (latente) : le même comportement de routage des chemins au pluriel existe structurellement sur suppliers/manufacturers/vouchers/customers/orders/newsdesks/cms/sliders — ticket distinct prévu.

v2.22.0

26 mai 2026
API Slider : les diapositives promotionnelles constituent un nouveau type d’entité
  • Nouveaux points de terminaison : GET /slider(s), POST/PUT /slider, DELETE /slider/{ID}.
  • Trois nouvelles portées : slider:read, slider:write, slider:delete (ID 56 à 58).
  • Filtres : status, type, categories_id, content_id, language.
  • languages{} imbriqués avec title, description, direction, width, image, image_mobile, video, video_mobile.
  • Contexte : jusqu’à présent, les diapositives promotionnelles ne pouvaient être mises à jour que via le backend. Le nouveau point de terminaison permet, par exemple, de corriger a posteriori des liens de diapositives erronés via PUT /slider.

v2.21.0

19 mai 2026
Importation des commandes : modes « Totals », taxe automatique et contrôle de dérive
  • Dérivation automatique à partir de customers_group_id — Charge utile en cascade → Fiche client → 0 (invité).
  • Déduction automatique depuis tax_flag à partir de customers_groups.show_tax + customers_groups.tax_exempt (0 = net, 1 = brut, 2 = exonéré d’impôt). Les valeurs explicites de la charge utile ont la priorité.
  • Trois modes de calcul des totaux (totals_mode) : auto (par défaut, se fier aux prix fournis par l’appelant), recalc (rechargerproducts_price + products_tax depuis la base de données, prise en compte du groupe de clients et du pays — idéal pour les importations depuis une place de marché avec uniquement le SKU et la quantité), verbatim (totals.total est conservé à l’identique, idéal pour les remboursements et les réimportations historiques).
  • Contrôle de dérive de bout en bout via expected_total + strict_totals. En cas d’écart > 0,01 € : par défaut = avertissement, avec strict_totals: true = interruption atomique via OrderBuilderException('TOTAL_DRIFT', 422) avant la première insertion des totaux.
  • Validation par liste blanche pour toutes les entités « Orders » (orders, order_address, order_product, order_totals, order_external_reference) — les clés inconnues génèrent un avertissement de déduplication « UNKNOWN_FIELD », comme pour les produits/clients.
  • Suite PHPUnit: 17 tests, 33 assertions (core/lib/classes/Tests/Order/OrderBuilderTest.php).

v2.20.0

19 mai 2026
Point de terminaison « Commandes » et webhook générique
  • Nouveau point de terminaison POST/PUT /Import/JSON/orders avec la portée orders:write — créer et mettre à jour des commandes via l’API.
  • Service générique \\Xonic\\Order\\OrderBuilder (core/lib/classes/Order/OrderBuilder.php) — réutilisable pour les importateurs Marketplace et WaWi.
  • Exceptions typées via \\Xonic\\Order\\OrderBuilderException avec errorCode, httpCode et details.
  • Calcul de la taxe : prend en charge le mode brut (tax_flag=1) et le mode net (tax_flag=0).
  • Enregistrement des stocks via xo_stock_change (best-effort : les échecs sont renvoyés sous la forme warnings ).
  • Suivi des références externes : enregistrement automatique dans TABLE_ORDERS_EXTERNAL_REFERENCES en cas d’ID externe.
  • Réaction marketing send_webhook — webhook sortant générique avec signature HMAC-SHA256 et charge utile enrichie (produit, commande, client, ticket).

v2.19.0

15 mai 2026
Point de terminaison média : téléchargements d’actifs statiques (entity_type=static)
  • Nouveau mode entity_type=static dans le point de terminaison multimédia — permet le téléchargement de ressources de marque (logos, images d’interface) sans liaison à la base de données.
  • Configuration de la liste blanche: dossiers de destination autorisés via XOPORT_MEDIA_STATIC_FOLDERS (par défaut : schnittstellen,marketplaces) — empêche les attaques par traversée de chemin.
  • Champs obligatoires: entity_type, target_folder, file_name ainsi qu’une source (file_url, file_base64 ou téléchargement multipart).
  • Comportement par défaut: écrase les fichiers existants (overwrite=true). La réponse contient le chemin d'accès direct à l'image.
  • Restrictions: pas d’enregistrement dans la base de données, pas de vignettes, pas de DELETE, pas de titres multilingues. Une requête PUT avec static est rejetée avec le code d’erreur STATIC_UPDATE_NOT_SUPPORTED.
  • Cas d'utilisation: gestion via l'API des logos de la place de marché, de l'habillage de l'interface et des ressources statiques du front-end.

v2.18.0

12 mai 2026
Import/export de produits : ventes incitatives (ajouts au panier)
  • Nouveau champ « upsells » dans le point de terminaison « Products » — similaire à « xsells », mais pour les suggestions « À associer » dans le panier (tableau products_upsell).
  • Export: pour chaque produit, un tableau contenant products_model, products_id (source) et sort_order. L'exportation d'un seul produit fournit les ventes incitatives du produit demandé (filtre sur le PID source).
  • Importation via PUT: accepte un simple tableau de chaînes de caractères représentant des modèles (["MODEL-A", "MODEL-B"]) ou un tableau d’objets ([{"products_model": "MODEL-A", "sort_order": 0}]).
  • Sémantique de remplacement: les ventes incitatives existantes sont entièrement supprimées avant l’insertion (DELETE puis INSERT). Les références à elles-mêmes et les modèles inconnus sont ignorés sans avertissement.
  • Cas d’utilisation: remplissage des suggestions de produits complémentaires dans le panier via l’API — configurable individuellement pour chaque produit (pas de liste globale par défaut).

v2.17.0

7 mai 2026
Importation de produits : extension des offres spéciales
  • Bloc « Offres spéciales » complet : specials[] par produit avec customers_group_id, prix spécial direct ou discount_percent.
  • Période et statut : specials_begin, specials_end (alias expires_date) ainsi que status/special_status.
  • Dénominations des offres : specials_price_id ou specials_price_name (en fonction de la langue) avec mise à jour automatique de slp.
  • Mise à jour et suppression : « upsert » via (products_id, customers_group_id), suppression via action: delete ou delete: 1. L'ancien bloc special reste rétrocompatible.

v2.16.0

29 avril 2026
API Media – Point de terminaison /media entièrement implémenté
  • Prise en charge CRUD complète : exportation (GET), importation (POST/PUT) et suppression (DELETE) pour la bibliothèque d’images de produits (products_images) — jusqu’à présent, toutes les opérations étaient des stubs 501 Not Implemented.
  • Trois modes de téléchargement : file_url (téléchargement depuis le serveur via cURL), file_base64 (en ligne) et multipart/form-data ( file de champ). Choix en fonction du client et de la taille du fichier.
  • Validation : détection MIME (image/jpeg|png|gif|webp), limite de taille de fichier via XOPORT_MEDIA_MAX_FILESIZE (par défaut 10 Mo), prévention automatique des conflits, nettoyage des noms de fichiers.
  • Titres multilingues : descriptions[] avec language_id ou language_code par image. La requête PUT avec descriptions remplace l’intégralité (sémantique de synchronisation complète).
  • Promotion de l’image principale : l’utilisation facultative de is_main=1 lors d’un POST définit en plus products.products_image.
  • Vignettes à la demande : les URL pour mini/small/medium/large/xlarge sont renvoyées dans chaque réponse — la génération physique s'effectue à la volée via image_thumb.php lors du premier appel.
  • Suppression sécurisée (DELETE) : supprime l’enregistrement, les lignes de description, le fichier source et toutes les vignettes — mais uniquement s’il n’existe plus aucune autre référence de la base de données pointant vers ce nom de fichier. Suppression en masse via ?entity_id= ou {ids:[…]}.
  • Nouvelles portées : media:read, media:write, media:delete.

v2.15.0

23 avril 2026
Importation de produits : champs « Famille/Variantes » + correction automatique des conflits SEO
  • Champs « Famille/Variantes » lors de l’importation : products_family (balise de chaîne), products_family_type (entier, 3= maître-esclave des variantes) et products_master (entier, PID du maître ou auto-référence) sont désormais acceptés — ce qui permet les regroupements maître-esclave (par exemple, variantes de packs) via l’importation JSON
  • Workflow maître-esclave : créer le maître → lire le PID à partir de records[0].products_id → effectuer un deuxième PUT avec products_master = eigene PID pour l’autoréférence, puis attribuer les esclaves
  • Contrôle d’unicité SEO : lors de l’importation, seo_name (ou, à défaut, products_name_as_seo) est comparé à tous les autres produits — de la même manière que dans la logique du backend
  • Correction automatique : en cas de conflit de slug, le nom est automatiquement corrigé en <slug>-<PID> (via tep_search_new_seo()) — l’importation se poursuit success: true
  • Avertissements de réponse : les corrections sont signalées dans warnings[] avec type: "SEO_NAME_CORRECTED", y compris requested, corrected et conflicting_with.{products_id, products_model, products_name}
  • Couvre une faille existante : le backend signaledésormais les conflits de slugs, alors que l’API les ignorait jusqu’à présent et générait des produits introuvables

v2.14.0

22 avril 2026
Importation de produits : alias courts pour les champs méta-SEO
  • Nouveaux alias courts : title_tag, desc_tag, keywords_tag sont désormais acceptés dans l’importation de produits — en cohérence avec l’API des catégories
  • Mappage interne : les alias sont mappés aux colonnes de la base de données products_head_title_tag, products_head_desc_tag et products_head_keywords_tag
  • Priorité : les noms complets des colonnes ont la priorité lorsque les deux variantes sont envoyées
  • Rétrocompatibilité : les charges utiles existantes contenant les noms de champs longs fonctionnent sans modification
  • Exportation : continue de fournir les champs products_head_*_tag(et non les alias)

v2.13.0

20 avril 2026
Historique SEO : redirections automatiques pour tous les types d’entités
  • En cas de changement de nom via une importation JSON (PUT), des entrées « seo_history » sont désormais créées automatiquement pour les produits (p), les catégories (c), les fabricants (m), les actualités (n) et le CMS (s) — les anciennes URL sont redirigées vers les nouvelles via une redirection 301
  • Produits : correction — fonctionne désormais également en cas de changement de nom SANS seo_name explicite (via la régénération automatique products_name_as_seo)
  • Fabricants : indépendant de la langue (une entrée sh_history, une ligne de description par langue avec le même slug)
  • Actualités et CMS : spécifiques à chaque langue (comme les catégories/produits)
  • Idempotent : une même charge de renommage ne génère pas de deuxième entrée
  • Aides « persistSeoHistory() » + « buildSeoHistoryDeletestamp() » extraites de « ImportJSON » (DRY)

v2.12.0

20 avril 2026
Liste des produits par catégorie (point de terminaison allégé)
  • Nouveau sous-point de terminaison : GET /categories/productlist — Mappage allégé des catégories vers les identifiants de produits et les modèles
  • Paramètres de requête : ?categories_id=, ?status=, ?include_inactive_products=, ?language=
  • Réponse : par catégorie, un tableau contenant categories_id, categories_name, products_count et products[], ainsi que id + model
  • Économie de mémoire : une seule requête SQL au lieu de plus de 12 relations
Pagination au niveau SQL pour les produits
  • Correction : GET /products utilise désormais la pagination au niveau SQL (LIMIT/OFFSET directement dans la requête)
  • Avant : tous les produits + relations chargés en mémoire, puis array_slice()
  • Après : seule la page demandée est chargée depuis la base de données — plus aucune limite de mémoire
  • Récupération individuelle via /products/{id} et les plages reste inchangée

v2.11.0

13 avril 2026

  • Tickets CRUD complet : points de terminaison d’importation (POST/PUT) et de suppression pour les tickets. Les portées « tickets:write » et « tickets:delete » sont désormais actives.
  • Export : linked_appointments[]: les rendez-vous CRM associés sont désormais inclus dans l’export pour chaque ticket (ID du rendez-vous, heure de début/fin, titre, description, lieu).
  • Import POST (Créer) : champs obligatoires ticket_subject, ticket_customers_email, ticket_customers_name. Génère ticket_link_id, crée le répertoire de téléchargement, commentaire initial facultatif + attributions d’administrateur.
  • Importation PUT (Mise à jour) : modification du statut/de la priorité/du service, ajout de commentaires internes (ticket_internal_comment=1 toujours). admin_id est un champ obligatoire pour les commentaires (0 = système).
  • Suppression : suppression en cascade (status_history → admins → followers → appointments_relationships → CRM followers → fichiers → ticket).
  • Portées : tickets:write (importation/mise à jour), tickets:delete (suppression) – auparavant marquées comme « prévues », désormais pleinement opérationnelles.

v2.10.0

9 avril 2026

  • Pagination globale : tous les points de terminaison d’exportation prennent en charge ?limit=n&offset=n. Limite par défaut : 50, limite maximale : 250 (configurable via XOPORT_API_MAX_LIMIT / XOPORT_API_DEFAULT_LIMIT). La réponse contient stats.count, stats.limit, stats.offset, stats.has_more.
  • Tickets – Nouveaux filtres : ?admin_id=n pour les tickets attribués (INNER JOIN sur ticket_to_admins) et ?created_by_admin_id=n pour le filtre par créateur.
  • Protection de la mémoire : la pagination automatique pour les grands ensembles de données empêche l'épuisement de la mémoire.

v2.9.0

8 avril 2026

  • API des tickets (exportation) : nouveaux points de terminaison GET /tickets et GET /ticket/{id} pour l’exportation des tickets avec l’historique complet des conversations, les administrateurs assignés et les abonnés.
  • Points de terminaison pour les pièces jointes : GET /ticket_attachments/{id} pour la liste des métadonnées (nom, taille, type MIME) et GET /ticket_attachment/{id}?file=name pour le téléchargement binaire avec protection contre le parcours de chemin.
  • Filtres de requête : ?status=, ?priority=, ?department=, ?customer_id=, ?type=, ?date_from=&date_to=, ?last_modified=, ?language=
  • Nouveaux scopes : tickets:read (implémenté), tickets:write, tickets:delete (implémenté dans la version 2.11.0)
  • Métadonnées : ticket_statuses, ticket_priorities, ticket_departments dans chaque réponse

v2.8.1

11 mars 2026

  • Correction de bug : Catégories last_modified: désormais toujours définies lors des mises à jour PUT — même si seules les données languages(description, nom, etc.) sont mises à jour. Auparavant, last_modified n’était mis à jour que si des champs de la table principale (status, parent_id, etc.) étaient également envoyés.
  • Newsletters ALLOWED_FIELDS: languages ajouté à la liste des champs autorisés — plus d’avertissement « UNKNOWN_FIELD » lors de l’importation de newsletters multilingues.

v2.8.0

6 mars 2026

  • API des abonnés aux newsletters : nouveaux points de terminaison pour les abonnés aux newsletters (exportation/importation/suppression) avec prise en charge des DOI.
  • API des campagnes de newsletter : nouveaux points de terminaison pour les campagnes de newsletter (exportation/importation/suppression) avec format multilingue.
  • Nouveaux scopes : newsletter:read, newsletter:write, newsletter:delete, newsletters:read, newsletters:write, newsletters:delete
  • Prise en charge des DOI : SHOP_NEWSLETTER_DOUBLE_OPT_IN La configuration est respectée, e-mail de confirmation lorsque le DOI est activé.
  • Synchronisation avec les fournisseurs : synchronisation automatique avec des fournisseurs externes (Cleverreach, Mailchimp, Optimizely) via xoNewsletter.
  • Conformité au RGPD : journalisation de la confidentialité lors de l'importation/la suppression, suppressions en cascade documentées.
  • Contrôles de sécurité : campagnes verrouillées protégées (409 LOCKED), newsletters envoyées non supprimables (409 HAS_SENT_ENTRIES).
  • Filtres d'abonnés : ?status=confirmed|unconfirmed, ?email=, ?customer_id=, ?language_id=, ?last_modified=
  • Filtre par campagne : ?status=, ?language_id=
  • Suppression en masse : possibilité de supprimer plusieurs abonnés via le corps JSON (par ID ou par e-mail)

v2.7.0

25 février 2026

  • API Contracts : nouveaux points de terminaison pour les contrats/abonnements (exportation/importation/suppression).
  • Point de terminaison « Status » : point de terminaison dédié PUT /contracts/{id}/status pour les changements de statut.
  • Nouveaux champs d'application : contracts:read, contracts:write, contracts:delete, contracts:write
  • Filtres de requête : ?status=, ?customer_id=, ?product_id=, ?interval=, ?date_from=&date_to=, ?active=1
  • Données imbriquées : attributs, domaines, historique des statuts, commandes
  • Suppression en cascade : attributs → domaines → liens de commande → historique des statuts → contrat

v2.6.0

24 février 2026

  • API d'historique SEO : nouveaux points de terminaison pour les redirections SEO (exportation/importation/suppression).
  • Redirection automatique : en cas de modification du « seo_name » lors de l’importation JSON d’un produit ou d’une catégorie, des entrées d’historique SEO sont automatiquement créées (de la même manière que pour l’importation XML).
  • Nouveaux champs d’application : seohistory:read, seohistory:write, seohistory:delete
  • Filtres de requête : ?type=, ?base_id=, ?language=, ?expired=1
  • Suppression en masse : suppression via le corps JSON ou un filtre de requête

v2.5.0

23 février 2026

  • Champs produit étendus : 19 nouveaux champs pour les données contractuelles et logistiques dans l'importation de produits.
  • Champs contractuels : contract, contract_use_current_price, contract_option — Les produits contractuels peuvent désormais être entièrement créés via l’API.
  • Champs logistiques : products_cost, products_inventory_management, products_min_qty, products_max_qty, products_qty_blocks, products_base_price
  • Champs « Article » : products_sort_order, products_ean, products_free_shipping, products_image
  • Indicateurs : service, sitemap, non_cart, non_price
  • Mappages : shipping_profile, products_unit_id, base_unit_id

v2.4.2

19 février 2026

  • Importation de produits : format « languages » imbriqué : cohérent avec l'exportation et toutes les autres entités (catégories, rédactions, CMS). Accepte les {"languages": {"de": {...}, "en": {...}}} avec des codes ISO ou des identifiants numériques.
  • Remplissage automatique lors de l'insertion (INSERT) : les langues manquantes sont automatiquement renseignées à partir des données de la langue principale.
  • Suppression du format plat : products_name + language_id au niveau supérieur n’est plus pris en charge.
  • Aller-retour symétrique : Export → Import → Export donne des données identiques.

v2.4.1

19 février 2026

  • Champs SEO dans l’importation de produits : 7 nouveaux champs : products_head_title_tag, products_head_desc_tag, products_head_keywords_tag, seo_name, products_url, products_checkout_description, products_image_title
  • Permet un aller-retour complet d'exportation→importation pour tous les champs de description des produits.

v2.4.0

6 février 2026

  • Point de terminaison CMS : nouveau type d'entité cms avec opérations CRUD complètes (exportation/importation/suppression).
  • Nouvelles portées : cms:read, cms:write, cms:delete
  • Contrôles de sécurité : pages système (ID 1 à 999) protégées, content_lock respecté
  • Paramètres de requête : ?status=, ?module=, ?language=
  • Prise en charge multilingue avec le format languages imbriqué

v2.3.0

31 janvier 2026

  • CRUD fournisseurs : nouveaux points de terminaison pour les fournisseurs (exportation/importation/suppression)
  • Extension de l'exportation de produits : champs videos, suppliers, contenteditor
  • Importation de produits étendue : categories_ids, groups, specials, extra_fields, badges, xsells, tabs, videos, suppliers, contenteditor
  • Importation des fabricants : tous les champs GPSR (coordonnées UE + hors UE)
  • Nouveaux domaines d'application : suppliers:read/write/delete
  • Stubs : marketing, newsletter, points de contact médias (501 pas encore implémenté)

v2.2.0

27 janvier 2026

  • Avertissements relatifs aux champs inconnus : la réponse contient désormais un tableau « warnings » pour les champs inconnus/ignorés
  • Déduplication : chaque champ inconnu n'apparaît qu'une seule fois, même en cas d'importation en masse de plus de 100 enregistrements
  • Champs imbriqués : vérifie également les objets ` languages.* ` et ` addresses[] `
  • Non bloquant : la requête est traitée avec succès malgré les avertissements (loi de Postel)
  • Objet « Warning » : {type, field, entity, message, first_occurrence}

v2.1.0

27 janvier 2026

  • Séparation des méthodes HTTP RESTful :
    • POST = uniquement INSERT (création de nouveaux enregistrements)
    • PUT = uniquement UPDATE (mise à jour d'enregistrements existants)
  • Validation stricte : POST avec un ID existant → 409 Conflict, PUT avec un ID inconnu → 404 Not Found
  • Nouveau champ de réponse : tableau « records » contenant « {index, entity_id, status} » pour chaque enregistrement
  • Code HTTP 405 « Method Not Allowed » en cas de méthode incorrecte (par ex. DELETE sur le point de terminaison d’exportation)
  • Les 8 points de terminaison d’entité prennent en charge POST/PUT : categories, products, customers, manufacturers, newsdesks, newsdeskcats, faq, faqcats

v2.0.3

26 janvier 2026

  • Points de terminaison DELETE pour newsdesks et newsdeskcats
  • Contrôles de sécurité : les catégories comportant des sous-catégories ou des articles associés ne peuvent pas être supprimées
  • Codes d'erreur : HAS_SUBCATEGORIES, HAS_NEWS
  • Vidéage du cache après une commande DELETE

v2.0.2

26 janvier 2026

  • Newsdesk categories_ids lors de l'exportation et de l'importation
  • Les articles d'actualité se voient attribuer des catégories (comme les produits)
  • Vidéos de cache après l'importation de newsdesks/newsdeskcats
  • Importation de « newsdesks/newsdeskcats » au format « languages » imbriqué

v2.0.1

26 janvier 2026

  • Importation des catégories au format « languages » imbriqué
  • Clés de langue utilisables sous forme de code (de, en) ou d'ID
  • Interface d'administration des clients OAuth2 avec recherche en temps réel et tri
  • Journalisation de la charge utile avec le corps de la requête/réponse

v2.0.0 Changements majeurs

26 janvier 2026

  • CHANGEMENT MAJEUR : identifiants des clients OAuth2 (RFC 6749)
  • Suppression des clés API – migration vers OAuth2 requise
  • Nouveaux points de terminaison : POST /oauth/token, GET /me
  • Nouvelles tables : xoport_oauth_clients, xoport_oauth_tokens
  • Préfixe de jeton : xoat_, Préfixe d'ID client : xoc_
  • Backend : Outils → Clients OAuth2 xoPort

v1.5.0

26 janvier 2026

  • Points de terminaison FAQ (faq/faqcategories Export/Import/Delete)
  • /me Point de terminaison pour l'introspection de la portée

v1.4.x

23 janvier 2026

  • Points de terminaison DELETE pour les catégories, les produits, les fabricants et les clients
  • Contrôles de sécurité contre la suppression accidentelle
  • Correction d'un bug : double échappement dans les attributs HTML corrigé

v1.0.0 - v1.3.x

23 janvier 2026

  • API JSON initiale avec exportation/importation
  • Gestion multi-adresses pour les clients
  • Importation de catégories avec auto-seo_name
  • Filtre par langue, codes pays ISO-2
  • Authentification par clé API (obsolète dans la v2.0)

Restez toujours à jour

En cas de changements majeurs, nous vous en informons via la newsletter.