Passer au contenu
megapromotingDiscutons

Expertise · Magasins en ligne

Un magasin dont le catalogue est lu en temps réel, pas copié une fois puis oublié.

Nous construisons des boutiques et, au-dessus, la couche qui manque habituellement : l’agent qui répond au client lit le prix et le stock directement dans la boutique, au moment de la question, et refuse d’inventer un prix non publié.

Déjà construitSe poate verifica din exterior chiar acum, fără să ne întrebi pe noi. Punctul nostru de catalog livrat unui distribuitor răspunde 200 și spune „154 rezultate”; interfața publică a magazinului lui, interogată direct, întoarce antetul `x-wp-total: 154`. Aceeași cifră, două surse independente, verificat pe 06.09.2026. A doua implementare e integrată în platforma de asistenți: serviciul `storeCatalog.service.js` plus trei unelte pe care agentul le poate chema. Rezerva care trebuie spusă: acest al doilea traseu stă pe o ramură de dezvoltare (`feat/store-catalog-global`, `481cfa0`) și nu e încă unificat în trunchi — deci e livrat pentru clienții pe care i-am conectat, nu pornit implicit pentru toți.

La plupart des « intégrations de catalogue » sont en réalité un export. Quelqu’un télécharge les produits une fois, les colle dans un fichier, et à partir de là l’agent qui parle avec le client lit une vieille photo du magasin. Cela fonctionne impeccablement jusqu’au premier changement de prix ou au premier produit épuisé — et alors il se trompe avec conviction, ce qui est pire que de se taire.

Nous lisons le magasin au moment de la question. Pour les magasins WooCommerce, il existe une interface publique — Store API — qui renvoie les produits, les prix et la disponibilité sans clés, sans compte, sans plugin installé. L’adresse est `/wp-json/wc/store/v1/products`, nous l’appelons avec 100 produits par page, avec un délai maximal de 20 secondes, et nous apprenons depuis l’en-tête de la réponse combien il y a de pages, au lieu de deviner. La première page, nous la prenons seule ; le reste en parallèle.

Ce qui sépare une intégration correcte d’une intégration qui en a l’air, c’est la traduction du prix. Store API ne renvoie pas « 129,90 » ; elle renvoie une chaîne de chiffres en unités mineures et, séparément, le nombre de décimales de la monnaie. Celui qui divise par 100 par habitude se trompe silencieusement pour toute monnaie qui n’a pas deux décimales. Et plus important encore : un prix zéro ne veut pas dire gratuit, il veut dire non publié. Chez nous, zéro devient « prix sur demande — à confirmer par les collègues », et l’agent reçoit l’instruction explicite de ne rien inventer. Cela se voit dans la réponse publique du point de catalogue, dès maintenant.

Au catalogue s’ajoutent les autres pièces, chacune avec son état réel : panier et envoi de commande vers le système de gestion du restaurant ou du magasin, paiement via l’interface MAIB pour les commerçants ou via Stripe, récupération des paniers abandonnés, suivi de l’état de la commande avec synchronisation toutes les 15 minutes. Là où nous n’avons pas d’intégration fonctionnelle — et il y a de tels cas — écrivez ci-dessous exactement laquelle.

Ce que cela comprend

Le travail, par composantes

Catalogue lu en temps réel, sans clés et sans plugin

Pour WooCommerce, nous utilisons Store API, l’interface publique du magasin : `/wp-json/wc/store/v1/products`, 100 produits par page, délai maximal de 20 secondes, un identifiant client propre dans l’en-tête et l’acceptation exclusive du code 200. Le nombre de pages, nous le lisons dans l’en-tête `x-wp-totalpages`, et le total des produits dans `x-wp-total` — nous ne paginons pas jusqu’à être démasqués. La première page est prise seule, le reste en parallèle, avec un plafond de 30 pages. Rien n’est installé dans le magasin et aucune clé marchand ne nous est donnée.

Le prix correctement traduit, et zéro traité comme non publié

L’API Store renvoie le prix sous forme de chaîne en unités mineures, plus le nombre de décimales de la devise. Nous divisons par dix à la puissance de ce nombre, et non pas par 100 fixe — sinon toute devise avec un autre nombre de décimales ressort fausse et personne ne le remarque. Zéro devient `null`, et dans la réponse apparaît « prix sur demande — à confirmer par un collègue », avec l’instruction explicite donnée à l’agent de ne pas inventer et de demander la confirmation d’un collègue. Le prix part en deux formes à la fois : texte prêt à afficher pour l’interface et nombre pour la logique en arrière-plan.

Trois outils que l’agent peut appeler

Dans la plateforme d’assistants, le catalogue est exposé comme trois outils intégrés — recherche par mots, correspondance par un appareil ou un cas d’usage, et récupération d’un produit par identifiant. L’agent les voit sous les noms `catalog_cauta`, `catalog_potrivire` et `catalog_produs`, chacun avec ses paramètres déclarés. Lorsque la plateforme de la boutique n’est pas celle attendue ou que l’adresse manque, l’outil refuse explicitement au lieu de renvoyer une liste vide qui serait interprétée comme « nous n’avons pas le produit ».

Les mots de liaison ne dégradent pas le résultat

« Filtre à eau » recherché littéralement correspond à tout ce qui contient « de ». Dans le point de catalogue livré et dans la recherche du widget vocal, nous coupons la liste de mots vides — `si`, `sau`, `de`, `din`, `la`, `cu`, `pe`, `in`, `pentru` — et, si après la coupe il ne reste plus rien d’utile, nous revenons aux mots de plus de deux lettres. La correspondance partielle a un seuil : un produit entre dans les résultats uniquement s’il atteint au moins la moitié des mots restants.

Quand la boutique n’a pas d’interface, nous lisons la page

Toutes les boutiques n’ont pas d’API Store. Pour les autres, nous avons un extracteur qui ouvre les pages de listing et lit leurs cartes produit, avec un budget écrit dans le code : maximum 20 pages de listing, 200 produits, 24 pages de détail, 50.000 de caractères HTML par page, 5 secondes par requête et un délai limite de 45 secondes pour toute l’opération. Il lit d’abord les données structurées de type produit de la page, puis les cartes, puis les métadonnées de partage — dans cet ordre, parce que la première source est celle que la boutique a écrite intentionnellement.

Fraîcheur avec des limites écrites, pas avec de l’espoir

Le catalogue est conservé en mémoire 10 minutes par boutique, et les requêtes simultanées pour la même boutique sont fusionnées en une seule, afin que dix clients qui demandent au même moment ne produisent pas dix téléchargements. Sur le point public du catalogue, la réponse porte aussi une instruction de cache pour le réseau de distribution : 5 minutes fraîche, encore 10 minutes servie périmée pendant qu’elle se rafraîchit en arrière-plan. Le nombre de résultats renvoyés est plafonné à 20, avec une valeur par défaut de 6.

Commande, panier et liaison avec le système de gestion

Le panier, l’envoi de la commande et sa remise au système de gestion du client sont des fonctions séparées, pas un formulaire. Il existe aussi la récupération des paniers abandonnés, la commande par conversation et le suivi de l’état de la commande, avec deux tâches planifiées qui s’exécutent toutes les 15 minutes — l’une synchronise le résultat des commandes, l’autre complète les états depuis le système de gestion sur une fenêtre de deux jours en arrière et un jour en avant.

Paiements : ce qui est fonctionnel et ce qui ne l’est pas

Fonctionnel et dans le code : l’interface MAIB pour les commerçants — jeton, puis demande de paiement, avec les identifiants de chaque boutique lus depuis la base de données et la fonction activée explicitement — et Stripe, avec montant converti en unités mineures et encaissement enregistré dans les écritures. Ce qui n’est PAS fonctionnel, pour qu’il n’y ait pas de surprises : Paynet, Netopia et mobilPay n’ont pas d’implémentation, et le code refuse explicitement lorsqu’ils sont demandés. Le trajet Moldindconbank est un squelette qui renvoie une erreur sans identifiants. Nous les prenons dans le projet comme travail, pas comme intégration existante.

L’agent n’invente pas quand le réseau tombe

Si l’interrogation de la boutique échoue, l’outil ne renvoie pas une liste vide — il renvoie un message qui dit à l’agent de ne pas formuler de réponse au sujet du catalogue. La différence est importante : une liste vide se traduit par « nous n’avons pas », et un « nous n’avons pas » dit à tort fait perdre une commande aussi sûrement qu’un prix erroné.

À quoi cela ressemble

Le parcours, étape par étape.

01

Vérification de la boutique, avant toute promesse

Nous interrogeons l’interface publique avec une seule requête, avec un temps d’attente maximal de 15 secondes, et nous lisons combien de produits elle a dans l’en-tête. À partir de cette réponse, nous savons si le trajet en direct est possible, combien de produits il y a et à quel point l’information de prix est complète. Si la boutique ne répond pas, nous le disons avant l’offre, pas pendant l’implémentation.

02

Connexion du catalogue et premier passage par les prix

Nous livrons la connexion, plus un passage en revue des produits avec prix zéro ou manquant — ce sont presque toujours de vrais produits, pas des erreurs, et la manière dont l’agent les traite est une décision du magasin, pas la nôtre. Nous livrons aussi le texte exact par lequel l’agent refuse de donner un prix non publié.

03

Les outils de l’agent et leurs limites

Nous mettons en place la recherche, la correspondance et l’apport d’un produit, chacun avec le nombre maximal de résultats fixé ensemble. Ici sont aussi écrits les synonymes propres au magasin — la façon dont le client appelle un produit par rapport à la manière dont le catalogue le nomme. Sans cette étape, la recherche est techniquement correcte et inutile en pratique.

04

La commande, le paiement et la liaison avec la gestion

Ils sont construits dans cet ordre, et chaque pièce n’entre qu’après vérification de l’accès réel au système de l’autre bout. Pour les paiements, on part seulement d’un fournisseur pour lequel nous avons une implémentation fonctionnelle ; le reste est traité comme un nouveau travail, avec le risque dit plus haut, et non comme une case cochée dans l’offre.

05

La remise, avec la liste des manques

Nous remettons les adresses, les configurations, les limites écrites dans le code et la liste de ce qui n’est pas couvert. Par exemple : le point public de catalogue livré n’a pas de temps d’attente maximal sur la requête vers le magasin — si le magasin répond très lentement, la requête se prolonge. C’est un manque réel, nous le mettons dans la liste de remise et dans le plan de corrections, pas dans une note interne.

Un centru. În jur, ce intră în el — pe trasee separate.CENTRUL SE SPRIJINĂ PE CE E ÎN JURUL LUI
Magazinul, agentul care răspunde, sistemul de gestiune și furnizorul de plată — patru sisteme separate, cu o singură sursă de adevăr pentru preț: magazinul, citit în momentul întrebării.

Les données

Ce que nous touchons, où elles sont et combien de temps elles restent

Les questions que pose toute personne ayant un délégué à la protection des données — posées ici avant qu'il ne les pose.

Données du catalogue
Nom, courte description, prix courant et prix catalogue, disponibilité, image, catégorie et adresse du produit — tous lus depuis l’interface publique du magasin, qui les publie de toute façon à tout visiteur. Nous ne copions pas la base de données du magasin et ne demandons pas de clés de commerçant. Elles restent chez le client ; nous les lisons à la demande.
Où elles sont conservées et pendant combien de temps
Le catalogue est conservé dans la mémoire du processus pendant 10 minutes par magasin et disparaît au redémarrage — il n’existe pas chez nous de copie persistante de celui-ci. Sur le point public de catalogue, le réseau de distribution le conserve encore 5 minutes comme version fraîche et 10 minutes comme ancienne version pendant le rafraîchissement. Un export figé, lorsqu’il constitue la seule option technique, est explicitement marqué comme instantané avec date, et non comme source vivante.
Les données de la conversation et de la commande
Ce que le client demande et ce qu’il commande passent par la plateforme de conversation et, le cas échéant, vers le système de gestion du magasin. Qui a accès, combien de temps cela est conservé et ce qui est supprimé sont établis pour le projet, avec le registre des traitements rédigé avant le démarrage, et non après le premier incident.
Les identifiants de paiement
Les identifiants de commerçant sont conservés dans la base de données de la plateforme, par magasin, et ne sont lus que lorsque la fonction de paiement est explicitement activée pour ce magasin. Ils n’atteignent pas la page publique et ne passent pas par la conversation. La configuration du compte marchand est effectuée par le titulaire du compte, pas par nous.
Ce que nous ne touchons pas
Nous ne prenons pas de données de carte. Nous ne demandons pas d’accès administrateur au magasin pour la lecture du catalogue — l’interface utilisée est publique. Lorsqu’un projet exige réellement un accès privilégié, il est demandé séparément, avec une finalité écrite, et n’est pas conservé « au cas où ».

Un cas

Un catalogue de 154 produits, lu au moment de la question

La situation

Un distributeur de café et d’eau à Chișinău, avec une boutique WooCommerce et des agents qui répondent aux clients par écrit et par téléphone. Le catalogue change souvent ; une liste copiée une fois devient fausse en quelques jours, et un mauvais prix dit au téléphone ne se retire pas.

Ce que nous avons construit

Nous avons monté un point de catalogue séparé, qui interroge l’interface publique de la boutique : 100 produits par page, le nombre de pages lu dans l’en-tête, la première page prise seule et le reste en parallèle, plafond de 30 pages. Le prix est traduit depuis les unités mineures selon le nombre de décimales déclaré par la boutique ; zéro devient « prix sur demande — confirmé par des collègues », avec une instruction écrite pour l’agent de ne pas inventer. La recherche coupe les mots de liaison et exige qu’un produit atteigne au moins la moitié des mots restants avant d’apparaître dans les résultats. La réponse est conservée 10 minutes en mémoire et 5 minutes dans le réseau de distribution, avec encore 10 minutes servies en version ancienne pendant le rafraîchissement. Les agents vocaux l’appellent comme un simple point web, pas comme une intégration spéciale.

Ce qui en est sorti

Vérifié le 06.09.2026, en deux requêtes indépendantes : le point de catalogue répond « 154 résultats » et liste le premier produit avec prix et disponibilité, tandis que le deuxième affiche « prix sur demande — confirmé par des collègues » ; interrogée directement, l’interface de la boutique renvoie `x-wp-total: 154`. Le même chiffre de deux sources qui ne se connaissent pas entre elles — c’est la vérification, pas notre déclaration.

Ce que le cas ne dit pas

Le point de catalogue livré n’a pas de délai maximal d’attente sur la requête vers la boutique : si la boutique répond très lentement, la requête se prolonge au lieu de tomber proprement. C’est un vrai manque, relevé à la relecture du code, et il figure dans la liste des corrections — pas dans la liste des fonctions. À part cela : le filtre de mots vides décrit plus haut est actif dans le point livré et dans la recherche du widget vocal ; dans la variante intégrée à la plateforme, il n’est pas encore porté, donc là une recherche avec beaucoup de mots de liaison donne des résultats plus larges.

Questions

Ce que les gens nous demandent avant d'appeler

Que signifie « catalogue vivant » et comment vérifier que ce n’est pas une formule ?

Cela signifie que l’agent lit la boutique au moment de la question. Cela se vérifie en deux requêtes, sans nous : notre point de catalogue pour un distributeur répond « 154 résultats », et l’interface publique de sa boutique, interrogée directement, renvoie dans l’en-tête `x-wp-total: 154`. Le même chiffre, deux sources indépendantes, à la même date. Un catalogue copié une fois ne peut pas faire cela — il se désynchronise au premier changement.

Dois-je vous donner des clés ou un accès à la boutique ?

Pour la lecture du catalogue sur WooCommerce, non. Store API est l’interface publique de la boutique : les mêmes données que voit tout visiteur, servies dans un format lisible par programme, sans clé marchand et sans plugin installé. Le commentaire est écrit directement dans notre code, pour ne pas se perdre. Nous demandons un accès privilégié seulement là où la fonction l’exige vraiment — par exemple pour l’envoi des commandes dans le système de gestion — et alors avec une finalité écrite.

Que se passe-t-il avec les produits sans prix ?

Ils sont traités comme non publiés, pas comme gratuits. Dans l’interface de la boutique, un prix absent arrive comme zéro, et une intégration naïve l’affiche « 0 MDL ». Chez nous, zéro devient « prix sur demande — confirmé par des collègues », et l’agent reçoit l’instruction explicite de ne pas inventer un chiffre et de demander la confirmation d’un humain. Cela se voit dans la réponse publique : le deuxième produit de la liste apparaît exactement ainsi.

À quel point le prix est-il frais, concrètement ?

Au maximum 10 minutes d’ancienneté au niveau de la plateforme, par boutique, et les requêtes simultanées pour la même boutique sont fusionnées en un seul téléchargement. Sur le point public de catalogue, le réseau de distribution sert pendant 5 minutes la version fraîche et encore 10 minutes la version ancienne, pendant qu’il la rafraîchit en arrière-plan. Les valeurs sont configurables par projet ; elles sont écrites comme des variables, pas cachées.

Ma boutique n’est pas sur WooCommerce. Que faites-vous ?

Cela dépend de ce qu’il expose. S’il a une interface propre, nous la lisons comme n’importe quelle autre. S’il n’a rien, nous avons un extracteur qui ouvre les pages de listing et lit les cartes produit, avec un budget écrit dans le code : 20 pages, 200 produits, 5 secondes par requête, délai limite de 45 secondes. Il lit d’abord les données structurées de la page, puis les cartes, puis les métadonnées de partage. C’est une solution de secours honnête, pas une solution équivalente : un magasin qui change son thème peut casser l’extracteur, alors qu’une interface non.

Quels paiements pouvez-vous intégrer dès maintenant ?

Fonctionnel et dans le code : l’interface MAIB pour les commerçants — obtention d’un jeton, puis requête de paiement, avec les identifiants de chaque boutique lus depuis la base de données et la fonction activée explicitement — et Stripe, avec le montant converti en unités mineures et l’encaissement enregistré. Ce qui n’est pas fonctionnel, dit avant le contrat : Paynet, Netopia et mobilPay n’ont pas d’implémentation, et le code refuse explicitement quand ils sont demandés ; le trajet Moldindconbank est un squelette qui renvoie une erreur sans identifiants. N’importe lequel d’entre eux peut être construit, mais cela entre comme un nouveau travail, avec son risque.

L’agent peut-il inventer un produit que vous n’avez pas ?

Peut-être, si vous ne l’en empêchez pas — et c’est de cela que nous nous chargeons. Trois barrières : le prix non publié vient avec une instruction écrite de ne pas inventer ; la mauvaise plateforme ou l’adresse manquante font que l’outil refuse explicitement, au lieu de renvoyer une liste vide ; et la panne réseau renvoie un message qui dit à l’agent de ne pas formuler de réponse sur le catalogue. La différence entre « liste vide » et « je n’ai pas pu lire » est la différence entre une commande perdue et une commande reportée par une phrase.

Pourquoi est-il important de savoir qui divise par 100 ?

Parce que l’interface n’envoie pas « 129,90 ». Elle envoie une chaîne de chiffres en unités mineures et, séparément, le nombre de décimales de la monnaie. Diviser par 100 est correct pour les monnaies à deux décimales et silencieusement faux pour les autres — personne ne reçoit d’erreur, seulement de mauvais chiffres. Nous divisons par dix à la puissance du nombre déclaré par la boutique. C’est une ligne de code, et c’est exactement le genre de ligne où l’on voit si quelqu’un a lu la documentation ou a deviné.

Que ne prenez-vous pas en charge ?

Nous ne prenons pas les données de carte et nous ne configurons pas le compte marchand à la place du titulaire. Nous ne garantissons pas qu’un extracteur de pages résiste à un changement de thème de la boutique — c’est pourquoi nous préférons l’interface lorsqu’elle existe. Nous ne promettons pas de hausse des ventes ; ce que nous pouvons montrer, c’est que le chiffre indiqué par l’agent coïncide avec le chiffre de la boutique, à la même date. Et nous ne présentons pas comme une intégration quelque chose qui, dans le code, n’est qu’un squelette : la liste ci-dessus dit ce qu’il en est.

Sur quoi reposent les affirmations ci-dessus (18 sources)
  1. Punctul de catalog livrat răspunde 200 și spune „Din catalogul <magazin> (154 rezultate, primele 2)”, cu al doilea produs marcat „preț la cerere — se confirmă de colegi”https://coffywater-ai.vercel.app/api/catalog?limit=2&scurt=1 · 2026-09-06
  2. Interfața publică a aceluiași magazin întoarce `x-wp-total: 154` și `x-wp-totalpages: 154` — aceeași cifră ca punctul de catalog, din sursă independentăhttps://coffywater.md/wp-json/wc/store/v1/products?per_page=1 · 2026-09-06

16 d'entre elles sont du code et des fichiers de nos dépôts. Nous n'en publions ni le nom ni la ligne : réunies sur une seule page, elles décriraient trop précisément comment sont construits des systèmes qui ne sont pas seulement les nôtres. Nous les parcourons avec vous, dans le dépôt, sur demande — la vérification reste possible, elle se fait simplement lors d'un échange.

Qu'est-ce que vous voudriez voir mieux fonctionner ?

Racontez-nous votre processus. Ensemble, nous décidons ce qui vaut la peine d'être construit, ce que nous pouvons connecter et comment nous vérifions le résultat.

Discutons