Documentation éditeurs
L'API du catalogue
Vous affichez nos produits sur votre site ; chaque clic part vers le marchand par un lien tracké qui vous attribue la vente. Tout se fait avec une clé d'API (pk_live_…), remise après votre inscription. Elle est montrée une seule fois — conservez-la comme un mot de passe. C'est aussi elle qui ouvre votre portail : vos statistiques, vos commissions, vos clés — sans mot de passe.
S'authentifier — deux formes, même clé
Pour essayer, la clé peut voyager dans l'adresse — collez ceci dans un navigateur :
https://universal-agent.ai/api/v1/products?market=FR&q=puzzle&cle=pk_live_VOTRE_CLEEn production, préférez l'en-tête d'autorisation — une adresse finit dans des journaux et des historiques, un en-tête non :
curl -H "Authorization: Bearer pk_live_VOTRE_CLE" \
"https://universal-agent.ai/api/v1/products?market=FR&q=puzzle"Le catalogue — GET /api/v1/products
Une page de produits d'UN marché. Les paramètres : market (pays en deux lettres, FR par défaut — les prix ne se mélangent jamais entre marchés), q (mots du titre), category (un rayon, descendance comprise), limit (50 max), cursor (la page suivante, telle que la réponse la donne) et site (voir plus bas). S'y ajoutent les facettes — type, matiere, couleur… — décrites plus bas.
{
"marche": "FR",
"produits": [
{
"id": "cp-104985",
"titre": "Short Fourth PSG Dri-FIT Stadium 2024/25",
"marque": "nike",
"gtin": "00197602201277",
"rayon": "Vêtements et accessoires > Vêtements > Shorts",
"rayonId": 207,
"image": "https://…",
"imageAffichage": "direct",
"marchands": 2,
"prixMiniCents": 4999,
"prixMaxiCents": 5499,
"devise": "EUR",
"occasion": { "marchands": 1, "prixMiniCents": 2990,
"prixMaxiCents": 2990, "devise": "EUR" },
"offres": [
{ "offre": "42137", "marchand": "Foot Store",
"prixCents": 4999, "devise": "EUR",
"lien": "https://universal-agent.ai/go/…",
"nature": "propre",
"etat": "neuf", "vendeur": "marchand",
"marchandShopify": false,
"compte": { "nom": "dealoshopping", "reseau": "awin",
"identifiant": "222222" } },
{ "offre": "51208", "marchand": "Espace Foot",
"prixCents": 5499, "devise": "EUR",
"lien": "https://universal-agent.ai/go/…",
"nature": "marketplace",
"etat": "neuf", "vendeur": "tiers",
"marchandShopify": true,
"compte": { "nom": "besttarget", "reseau": "awin",
"identifiant": "111111" },
"comptes": [
{ "compte": "besttarget", "nom": "besttarget", "reseau": "awin",
"identifiant": "111111", "tracable": true,
"lien": "https://universal-agent.ai/go/…" },
{ "compte": "dealoshopping", "nom": "dealoshopping", "reseau": "awin",
"identifiant": "222222", "tracable": true,
"lien": "https://universal-agent.ai/go/…" }
] }
]
}
],
"curseur_suivant": "Y3AtMTA0OTg1",
"total": 128
}compte nomme le compte d'affiliation qui encaissera ce clic : nom est son libellé chez nous (« besttarget »), identifiant son identifiant chez le réseau — le a= d'Awin qui part dans l'URL et qui décide qui est payé. C'est ce qui vous permet de rapprocher nos clics de vos propres rapports d'affiliation, ligne à ligne. Le champ est absent quand aucun compte n'atteint le flux de cette offre : le lien partira alors vers l'adresse marchande nue, sans commission — c'est rare, et ça se voit.
comptes liste tous les comptes qui atteignent ce marchand, chacun avec SON lien. Le produit n'est pas dupliqué pour autant : c'est le même article, au même prix, chez le même marchand — seul le bénéficiaire du clic change. Le premier de la liste est celui que le lien de l'offre sert : ne rien choisir reste valide, et c'est le cas normal. Prenez-en un autre si vous voulez répartir vos clics entre vos comptes.
tracable à false prévient que ce compte n'a pas encore de code de tracking pour ce programme : son lien conduira bien le visiteur chez le marchand, mais ne rapportera rien. Préférez alors un compte traçable. Nous préférons vous le dire que vous le laisser découvrir sur un relevé de commissions.
Si des comptes vous ont été attribués, votre catalogue s'y limite : les produits qu'aucun de vos comptes n'atteint ne vous sont pas servis, ni en liste, ni en fiche, ni en réponse. C'est volontaire — mieux vaut un catalogue plus court que des clics dont la commission part ailleurs sans que vous puissiez le savoir. Sans compte attribué, vous voyez le catalogue entier.
nature dit ce que vend le flux d'où vient l'offre, et c'est ce qui vous évite d'induire un acheteur en erreur sans le vouloir. Quatre valeurs : propre — le stock du marchand lui-même ; marketplace — un vendeur tiers hébergé par ce marchand, ce qui explique que le même nom revienne à plusieurs prix sur un produit : ce sont plusieurs vendeurs, pas plusieurs fois la même offre ; occasion — du reconditionné ou de la seconde main vendu par le marchand lui-même ; et occasion-marketplace — de l'occasion vendue par des tiers, qui cumule les deux cas précédents. Afficher un reconditionné à 249 € à côté d'un neuf à 399 € sans le dire ferait croire à une affaire qui n'existe pas : signalez-le, ou écartez ces offres de vos comparaisons de prix. Le champ est toujours présent ; en l'absence de tout indice, il vaut propre, qui est le cas ordinaire.
Les deux axes se lisent aussi à part, pour que vous n'ayez pas à découper un mot composé. etat vaut neuf ou occasion ; vendeur vaut marchand — le stock de l'enseigne nommée, « vendu par Darty » — ou tiers — un vendeur hébergé par elle, « vendu par un vendeur tiers sur Darty ». Le nom de ce vendeur tiers ne nous est pas donné par les flux : nous pouvons dire « sur Darty », jamais « par Untel », et nous ne l'inventons pas.
Les prix de tête ne comparent jamais deux états. prixMiniCents, prixMaxiCents et marchands ne comptent que les offres neuves. Le reconditionné a son propre bloc occasion, avec les mêmes trois nombres — ou null quand il n'y en a pas. Un produit qui n'existe qu'en occasion a donc prixMiniCents: null et tout dans occasion. C'est le partage qui vous permet d'écrire « Neuf dès 399 € · Occasion dès 249 € » sans jamais annoncer 249 € sur une fiche neuve.
La même règle vaut pour les liens /go/ : quand une offre disparaît du flux marchand, son lien rebondit vers la meilleure offre active du même état. Un lien vers du neuf ne renverra jamais vers du reconditionné ; faute de remplaçant neuf, le visiteur arrive chez le marchand d'origine.
marchandShopify dit si la boutique tourne sur Shopify. Vrai veut dire qu'elle expose https://<domaine>/products/<handle>.json publiquement et sans clé — prix, stock et variantes du jour. Là où notre flux vous donne le prix du dernier chargement, cette adresse vous donne le prix maintenant. Le handle est le segment qui suit /products/ dans l'adresse du produit. Faux veut dire « pas détecté » : une boutique Shopify au domaine personnalisé reste invisible depuis une adresse.
Les prix sont en centimes, dans une seule devise. L'id (cp-…) est notre identifiant de produit : stable, il sert à demander la fiche. total dit combien de produits répondent à la requête sans tout paginer — exact jusqu'à 10 000 ; au-delà, il s'arrête à 10 000 et total_plafonne: true l'accompagne. Une synchro qui pagine n'en a besoin qu'une fois : passez ?total=0 sur les pages suivantes, le comptage est sauté. Même plafond côté recherche : un mot très courant (« tapis », « robot ») sert les 10 000 premières fiches trouvées, classées par pertinence — et le total dit alors « au moins » : il compte les fiches vendables du vivier, d'autres correspondances existent au-delà. Précisez la requête pour resserrer.
Filtrer par facette — « les robes en lin pour femme »
Chaque produit porte des facettes — son type, sa matière, sa couleur, sa taille, son usage… Elles se demandent en français, sur la liste comme sur la réponse, et elles se cumulent :
https://universal-agent.ai/api/v1/products?market=FR&category=1604&type=robe&matiere=lin&genre=femmeTrois filtres veulent dire les trois à la fois, jamais l'un ou l'autre — un ET, pas un OU. Pour une union, faites deux appels et mélangez-les vous-même : nous préférons un paramètre qui dit exactement ce qu'il fait à un paramètre qui devine.
Les accents et la casse n'ont aucune importance : COTON, Coton et coton désignent la même valeur. Une facette que nous ne connaissons pas est ignorée, pas refusée — votre code ne casse pas le jour où nous en ajoutons une, et il profitera des nouvelles sans être modifié.
Les vingt-deux facettes filtrables : type, marque, genre, taille, couleur, matiere, usage, style, etat, motif, manches, col, coupe, fermeture, age, origine pour tout produit ; technologie, resolution, format, systeme, connectivite, norme pour l'électronique. Une facette absente d'un rayon y rend zéro — une robe n'a pas de dalle, et c'est honnête.
Chaque produit rendu porte SES facettes, avec le nom du paramètre qui les redemande. Afficher trente robes avec leur matière ne coûte donc pas trente appels de fiche :
"facettes": [
{ "param": "type", "nom": "Type de produit", "valeur": "robe" },
{ "param": "matiere", "nom": "Matière", "valeur": "Lin" },
{ "param": "couleur", "nom": "Couleur", "valeur": "Écru" }
]D'où viennent-elles ? Du marchand quand il les déclare, et sinon de la lecture de son titre et de sa description — un vocabulaire fermé, appliqué au catalogue entier. Nous n'écrivons jamais par-dessus ce qu'un marchand affirme : une facette déduite ne remplit que le vide.
Savoir sur quoi filtrer — GET /api/v1/facettes
Filtrer suppose de savoir quelles valeurs existent. Sans ça, on propose des filtres qui rendent zéro résultat. Cette lecture donne, pour un rayon, les facettes disponibles et le nombre de produits derrière chaque valeur — de quoi construire un menu :
https://universal-agent.ai/api/v1/facettes?market=FR&category=1604{
"marche": "FR",
"rayon": 1604,
"produits": 18432,
"tronque": false,
"facettes": [
{ "param": "type", "nom": "Type de produit",
"valeurs": [ { "valeur": "robe", "produits": 12841 },
{ "valeur": "jupe", "produits": 3120 } ] },
{ "param": "matiere", "nom": "Matière",
"valeurs": [ { "valeur": "Coton", "produits": 3180 },
{ "valeur": "Lin", "produits": 412 } ] }
]
}Les filtres déjà posés rétrécissent le menu suivant : ajoutez &matiere=lin et vous obtenez les couleurs des robes en lin, pas celles du catalogue. C'est ce qui fait la différence entre une liste de mots et un vrai menu de filtres.
valeurs borne le nombre de valeurs rendues par facette (30 par défaut, 200 au plus), les plus nombreuses d'abord. Au-delà de 25 000 produits dans le périmètre, tronque passe à true et les comptes valent « au moins » — un menu juste et rapide sert mieux qu'un menu exact et lent. Les proportions, elles, restent justes bien au-delà, et c'est ce qu'un menu montre vraiment.
La fiche — GET /api/v1/products/{id}
Tout ce que nous savons du produit : la description, l'image, les caractéristiques (couleur, dimensions, garantie…), et chaque offre du marché avec sa disponibilité et son lien.
https://universal-agent.ai/api/v1/products/cp-104985?market=FR&cle=pk_live_VOTRE_CLEChaque offre de la fiche porte aussi son historique : les derniers changements de prix (dix au plus), du plus récent au plus ancien — precedentCents, prixCents, le (la date). De quoi écrire « en baisse depuis le 12 » sans rien stocker chez vous. L'historique ne raconte que des mouvements : une offre au prix stable n'en a pas, et c'est normal.
La fiche compte comme la liste : chaque offre y porte les mêmes nature, etat et vendeur, et la fiche entière porte les mêmes prixMiniCents / prixMaxiCents / marchands — le neuf seul — avec le bloc occasion à part. Les deux chemins passent par le même calcul : deux règles pour un même nombre finiraient par diverger sans que personne ne le voie.
La réponse — GET /api/v1/reponse
L'entrée des chatbots et des encarts : une question libre en entrée (q), les produits les plus pertinents en sortie — avec leurs offres, leurs liens, leur image — et une phrase d'accroche calculée depuis ces données, jamais générée. Les tournures de question (« quels sont les meilleurs… ») sont comprises : seuls les mots de produit cherchent.
https://universal-agent.ai/api/v1/reponse?q=meilleurs biberons anti colique&cle=pk_live_VOTRE_CLE
{
"marche": "FR",
"question": "meilleurs biberons anti colique",
"phrase": "5 produit(s) pour « meilleurs biberons anti colique » chez 3 marchands ; le mieux placé : …",
"produits": [ { "id": "cp-…", "titre": "…", "image": "https://…",
"prixMiniCents": 1038, "occasion": null,
"offres": [ { "marchand": "…", "prixCents": 1038,
"etat": "neuf", "vendeur": "marchand",
"lien": "https://universal-agent.ai/go/…" } ] } ]
}Les produits de la réponse sont ceux de la liste, champs compris : etat, vendeur et le bloc occasion y sont. La phrase annonce le prix du neuf ; pour un produit qui n'existe qu'en reconditionné, elle dit « à partir de 249 € en occasion » — jamais un prix d'occasion présenté comme un prix neuf.
Paramètres : q (obligatoire), market, limit (10 max), site. Votre bot pose la question, vous affichez les produits — ou seulement la phrase.
Selon votre accord, la phrase peut être rédigée par un modèle d'IA (votre clé ou la nôtre) au lieu d'être calculée : le champ ia de la réponse dit ce qui a servi. Le modèle n'invente rien — il ne voit que les produits servis — et en cas d'indisponibilité la phrase calculée part à la place : la réponse arrive toujours. Activez-le vous-même dans votre portail en collant votre clé Anthropic (scellée, jamais réaffichée) — ou écrivez-nous pour un accord où la plateforme porte le coût.
Afficher les images — un attribut à poser
Les images sont servies à l'adresse où le marchand les héberge. Certains hébergeurs refusent une image dès que la page qui la demande n'est pas la leur : le navigateur envoie toujours l'adresse de la page d'origine (le « référent »), et l'image reste invisible sur votre site alors qu'elle s'ouvre très bien seule dans un onglet. Posez referrerPolicy="no-referrer" sur vos balises d'image : le navigateur n'envoie plus de référent, et ces images s'affichent.
<img src="{image}" referrerpolicy="no-referrer" loading="lazy" alt="{titre}">Chaque produit porte aussi imageAffichage, tiré d'essais réels chez l'hébergeur, refaits après chaque mise à jour des catalogues : direct — s'affiche partout ; sans_referent — s'affiche seulement avec l'attribut ci-dessus ; injoignable — l'hébergeur ne rend pas d'image, prévoyez un visuel de remplacement ; null — hébergeur pas encore vérifié.
Le widget et l'in-text — sans une ligne de code
Deux scripts prêts à coller, servis par nous, qui n'exposent jamais votre clé : ils portent un jeton public de site (pu_…, forgé dans votre portail, un par site). Le widget pose un encart « question → produits » sur votre page ; l'in-text transforme vos mots-clés en liens affiliés — donnez-lui vos mots (data-mots, deux liens par page au plus), ou annotez un mot précis (data-ua-q).
Le widget :
<script src="https://universal-agent.ai/editeurs/widget.js" defer
data-jeton="pu_VOTRE_JETON" data-market="FR"></script>L'in-text :
<script src="https://universal-agent.ai/editeurs/intext.js" defer
data-jeton="pu_VOTRE_JETON" data-market="FR"
data-mots="biberon, lit parapluie" data-max="2"></script>Derrière les deux, la même adresse publique : GET /api/embed/reponse?jeton=pu_…&q=… — CORS ouvert, bornée à six produits par appel, 5 000 appels par site et par jour. La mention « Liens affiliés » est affichée par le widget, et l'in-text pose rel="sponsored" — la transparence n'est pas une option.
La sélection et le comparateur — deux iframes
Deux pages hébergées, à poser dans un article avec le même jeton pu_… : la sélection (/embarque/selection?jeton=…&q=…&n=5) — un « top N » toujours à jour, l'inverse du contenu figé — et le comparateur (/embarque/comparateur?jeton=…&q=…) — les offres du produit le plus pertinent, marchand par marchand, triées par prix. Paramètres communs : market et titre (votre propre titre d'encart). Les extraits prêts à coller sont dans votre portail, jeton compris.
Le lien /go/ — la seule adresse vers un marchand
Chaque offre porte un champ lien : posez-le tel quel sur votre site. Au clic, nous journalisons, nous étiquetons le lien de vos références d'attribution, et nous redirigeons le visiteur chez le marchand. C'est ce qui vous attribue la vente. Les liens sont permanents : stockez-les, publiez-les, ils ne périment jamais. La destination se résout au clic — si une offre disparaît du flux, son lien rebondit vers la meilleure offre active du même produit au lieu d'une page morte. L'API ne donne jamais l'adresse marchande brute — le lien /go/ EST l'adresse.
Un réseau de sites ? Le site peut arriver au clic : ajoutez ?site=monsite.fr au lien, il prime le site du jeton. Vous synchronisez UNE fois — les mêmes liens pour tous vos sites — et chaque site appose son nom en posant le lien ; un site nouveau ne demande aucune resync, et l'attribution par site reste exacte.
https://universal-agent.ai/go/JETON?site=boutique-chaussures.frVotre propre suivi voyage aussi jusqu'au réseau. Ajoutez sub= pour votre identifiant de suivi et ref= pour la page d'origine, encodée — ou, si c'est l'écriture de vos liens, subid= et referer=. Au clic, chaque valeur part dans le paramètre que le réseau du marchand réserve à cet usage — et seulement ce que vous avez envoyé : rien n'est déduit ni complété pour vous.
https://universal-agent.ai/go/JETON?sub=newsletter-octobre&ref=https%3A%2F%2Fmonsite.fr%2FarticleVos valeurs partent dans l'emplacement que chaque réseau réserve au suivi, telles que vous les avez écrites. Chaque réseau a ses règles : une longueur maximale — 50 caractères chez certains, 64 chez d'autres — au-delà de laquelle la valeur est coupée plutôt que perdue, et parfois des minuscules imposées.
Pour le ménage : chaque offre de la fiche porte actif (faux quand elle a disparu du flux) et vuLe (sa dernière mise à jour), et la fiche entière porte actif. Une resync de temps en temps — trimestrielle, par exemple — suffit à repérer les produits morts et à les retirer de vos pages.
Vos rayons — GET /api/v1/categories
Les rayons qui portent des produits, avec leur identifiant — la valeur du paramètre category de la liste, descendance comprise : demander « Vêtements » rend aussi les shorts.
Vos chiffres — GET /api/v1/stats
Vos clics jour par jour (humains, dont affiliés ; robots comptés à part), site par site, vos fiches lues, votre usage du quota. Les commissions s'y rangeront prochainement — même adresse, champs en plus.
https://universal-agent.ai/api/v1/stats?cle=pk_live_VOTRE_CLEVous gérez plusieurs sites ?
N'inscrivez pas trois cents sites : une seule clé pour votre réseau, et le paramètre site= sur chaque appel (site=monsite.fr). Chaque site se déclare tout seul à son premier appel, les liens /go/ lui sont attribués, et vos statistiques se lisent site par site.
Les limites, dites d'avance
20 000 requêtes par clé et par jour — un site normal n'y touche jamais. Au-delà : HTTP 429. Une clé absente, révoquée ou un compte suspendu : HTTP 401, une seule phrase. Un paramètre illisible : HTTP 400, avec la raison. Les réponses se gardent en cache une minute.
Une question, une clé perdue, un besoin qui manque ? Écrivez-nous — une clé perdue se remplace en une minute, elle ne se retrouve pas.