La spécification du flux produit OpenAI définit 9 champs obligatoires (item_id, title, description, url, brand, seller_name, image_url, availability, price), un ensemble de champs recommandés pour les variantes, les identifiants et les prix promotionnels, et des champs optionnels pour les attributs, les médias, la livraison, la publicité et le paiement. Les valeurs suivent des formats stricts : la monnaie en 79.99 USD, les booléens en true/false, les identifiants sous forme de chaînes. Une ligne qui enfreint une règle est inutilisable, et la documentation ne décrit aucun rapport d’erreur ligne par ligne.
Pourquoi la formulation exacte des règles compte
La page de présentation du dépôt de fichiers cite les trois causes d’échec les plus fréquentes : « missing required fields », « outdated or non-spec field names » et « malformed field values ». Ce sont trois problèmes de format : le produit est bon, la ligne ne l’est pas. Comme la documentation ne décrit aucun rapport d’erreur ligne par ligne, un marchand ne découvre une ligne mal formée qu’en remarquant qu’un produit n’apparaît jamais dans ChatGPT. C’est pourquoi chaque règle ci-dessous est accompagnée d’un exemple rejeté. Les citations sont reprises mot pour mot de la spécification du flux produit et de ses deux pages associées listées dans les sources.
Les 9 champs obligatoires
Une ligne qui omet l’un de ces champs, ou qui fournit une valeur vide ou non reconnue, est inutilisable. La spécification est explicite pour availability : une valeur omise, vide ou non reconnue rejette la ligne.
| Champ | Type | Contrainte (d’après la spécification) | Exemple valide | Exemple rejeté |
|---|---|---|---|---|
item_id | chaîne | « Stable ID, unique per item or variant within your feed. Never reuse it for a different item. » | TRAIL-BLK-10 | Un numéro de ligne de base de données qui change à chaque réimport |
title | chaîne | « Product name, including the selected variant when relevant. » 150 caractères maximum, texte brut | Trail running shoes, black, size 10 | Un titre de 300 caractères bourré de mots-clés |
description | chaîne | « Factual product description for this item. » 5 000 caractères maximum, texte brut | Waterproof trail shoes with a rubber outsole and mesh lining. | <p>Waterproof <strong>trail</strong> shoes</p> |
url | URL | « Product detail page for the item, with the variant selected when possible. Keep it stable. » HTTP ou HTTPS absolue, accessible publiquement | https://example.com/products/trail?color=black&size=10 | /products/trail (chemin relatif) |
brand | chaîne | « Product brand as shown on the product page. » Une vraie marque, pas une valeur de remplissage | Northline | n/a |
seller_name | chaîne | « Name of the seller supplying this offer. » Un vrai nom, pas une valeur de remplissage | Northline Outdoor | unknown |
image_url | URL | « Main product image, showing this variant. Use a direct image URL, such as a JPEG or PNG. » | https://example.com/images/trail-black.jpg | https://example.com/products/trail (une page, pas une image) |
availability | énumération | « in_stock, out_of_stock, pre_order, backorder, or unknown. » | in_stock | available, preorder, In Stock |
price | monnaie | « Regular item price in major currency units. » Format amount CURRENCY | 79.99 USD | 79,99, $79.99, 79.99, 1,079.99 USD |
Trois détails de ce tableau causent l’essentiel des ennuis.
item_id doit survivre aux réimports. Un identifiant dérivé d’une position de ligne ou d’un horodatage transforme chaque instantané en nouveau catalogue. Utilisez le SKU ou l’identifiant de variante de la plateforme, sous forme de chaîne.
availability est une liste fermée. Google Shopping utilise preorder ; OpenAI utilise pre_order. Un flux copié depuis un export Google porte la mauvaise orthographe sur chaque produit en précommande.
price est une seule chaîne, pas deux colonnes. La spécification demande « a decimal amount in major units, a space, and an uppercase three-letter ISO 4217 currency code », avec « a decimal point, no thousands separators or exponent notation, and no more fractional digits than the currency permits ». Un prix exporté depuis un environnement français sous la forme 25,99 échoue sur le seul séparateur décimal.
Les champs recommandés
Ils ne sont pas obligatoires, mais une valeur mal formée dans un champ recommandé reste une valeur mal formée. Si vous ne pouvez pas renseigner un champ correctement, omettez-le.
Variantes : group_id, listing_has_variations, variant_dict
Les trois champs fonctionnent ensemble. group_id est un « Stable parent-listing ID shared by all variants. » La spécification ajoute : « Omitted or empty: uses item_id, which does not establish a variant group. » Un group_id copié depuis item_id ne produit donc aucun groupe, sans que rien ne le signale.
listing_has_variations doit valoir true sur chaque ligne de variante : « Omitted, empty, or false: no variant options are used. »
variant_dict associe des noms d’options à des valeurs sélectionnées, sous forme de chaînes. Il « Requires listing_has_variations=true and group_id different from item_id. » Les clés et les valeurs doivent être non vides, les mêmes noms d’options doivent être utilisés dans tout le groupe, et chaque combinaison d’options doit être unique. La spécification demande aussi de garder les attributs de premier niveau comme color et size cohérents avec les mêmes options dans variant_dict, parce que « Neither representation reconciles conflicting values for you. »
| Situation | Résultat |
|---|---|
group_id = TRAIL, item_id = TRAIL-BLK-10, listing_has_variations = true, variant_dict = {"color":"Black","size":"10"} | Groupe de variantes établi |
group_id = TRAIL-BLK-10 (identique à item_id) | Aucun groupe de variantes |
group_id renseigné, listing_has_variations omis | Aucune option de variante utilisée |
variant_dict = {} | Traité comme une absence d’options |
color = Blue au premier niveau, variant_dict.color = Black | Valeurs contradictoires, non réconciliées |
Identifiants : gtin, mpn, offer_id
gtin est « One assigned GTIN: exactly 8, 12, 13, or 14 digits, including a valid check digit. Preserve leading zeros; no spaces or dashes. » Deux conséquences : un GTIN avec une faute de frappe échoue au contrôle de la clé, et un GTIN exporté depuis un tableur qui a supprimé le zéro initial n’a plus la bonne longueur. Validez avant de téléverser.
mpn est le « Manufacturer-assigned part number, preserving its punctuation and casing. » La spécification est sans détour sur un raccourci courant : « do not invent a value to replace a missing GTIN. »
offer_id est un « Stable offer ID, unique within the feed. Use it to distinguish offers that share a product URL. » C’est une chaîne, donc les zéros initiaux sont conservés.
État et prix promotionnel
condition accepte new, refurbished ou used. Une valeur omise ou vide « may be treated as new », donc précisez toujours used ou refurbished quand cela s’applique.
sale_price est le « Current sale price: greater than zero, strictly less than price, and in the same currency. » Un prix promotionnel « Nonpositive, equal, higher, or different-currency » n’est pas utilisé. La spécification indique aussi quand le mettre à jour : « Submit the current price; update the feed when a sale starts or ends. » Ne programmez pas une promotion à l’avance en envoyant le futur prix.
price | sale_price | Résultat |
|---|---|---|
79.99 USD | 59.99 USD | Utilisé |
79.99 USD | 79.99 USD | Non utilisé (égal) |
79.99 USD | 59.99 EUR | Non utilisé (devise différente) |
79.99 USD | 0.00 USD | Non utilisé (nul) |
is_eligible_search
« true enables search eligibility; false disables it and checkout eligibility. Omitted or empty: true. » C’est l’interrupteur qui retire un produit rapidement : la page de présentation du dépôt recommande de passer is_eligible_search=false pour rendre un produit inéligible au prochain cycle de traitement, plutôt que de supprimer la ligne, parce qu’OpenAI « retains its most recently processed record for up to 14 days ».
Les champs optionnels, par groupe
Attributs de l’article
| Champ | Règle |
|---|---|
product_category | « Your category path, from broad to specific, separated by > », par exemple Apparel & Accessories > Shoes |
material | Matériaux principaux de l’article |
color | Couleur sélectionnée, cohérente avec l’image du produit |
size | Libellé de la taille sélectionnée ; utilisez variant_dict quand la taille distingue les variantes |
gender | male, female ou unisex ; toute autre valeur équivaut à une absence de genre |
age_group | newborn, infant, toddler, kids ou adult ; « a product attribute, not a purchase-age restriction » |
dimensions | Objet avec des chaînes décimales positives pour au moins deux des valeurs length, width, height, plus une unité (in, cm, ft, m, mm) ; un objet vide est invalide |
weight et item_weight_unit | Poids net positif sans emballage ; unité g, kg, oz ou lb ; l’unité est obligatoire avec le poids |
Médias
additional_image_urls est un tableau en JSON ou en Parquet, et une chaîne séparée par des virgules en CSV ou en TSV. Les URL invalides sont omises. Si une URL d’image contient elle-même une virgule, la spécification demande de « Percent-encode commas as %2C in URL », sinon le délimiteur coupe l’URL en deux.
Livraison et retours
| Champ | Règle |
|---|---|
shipping_price | Format monétaire, même devise que price, non négatif ; « zero = no charge. Omitted/empty = unknown, not free » |
shipping | Tuple country:region:service_class:price, en conservant la position vide de la région, par exemple US::Standard:5.00 USD |
accepts_returns | true ou false ; omis signifie non précisé |
return_deadline_in_days | Nombre entier positif, « Supply only with accepts_returns=true » |
return_policy | URL HTTP ou HTTPS publique vers les conditions de retour ou de vente ferme |
Avis et notes
review_count est un nombre entier non négatif d’avis produit (pas d’avis sur le vendeur ou la boutique) ; zéro signifie aucun avis, omis signifie inconnu. star_rating est une chaîne décimale sur une échelle de 0 à 5 avec deux décimales, par exemple 4.50, et doit être accompagnée d’un review_count positif correspondant.
Informations sur le marchand
seller_url pointe vers la vitrine ou la page de profil du vendeur (pour les offres de place de marché, la page du vendeur concerné). marketplace_seller nomme la place de marché où le paiement a lieu et nécessite une configuration avec OpenAI.
Publicité
is_ads_eligible : « Set true for products Ads should process; false explicitly opts out. Omitted/empty: disabled unless feed-level default applies. » Renseignez-le explicitement plutôt que de compter sur une valeur par défaut. ads_metadata est un objet chaîne vers chaîne qui utilise les clés configurées pour votre intégration publicitaire, par exemple {"custom_label_0":"summer"} ; « Do not invent keys. »
Paiement
is_eligible_checkout « true opts in only when search eligibility also true and checkout enabled. Omitted/empty/false: disabled. Search=false overrides this. » Quand vous activez cette option, publiez seller_privacy_policy et seller_tos sous forme d’URL publiques ; les fournir « does not establish checkout readiness » à lui seul.
Ciblage géographique
target_countries est un tableau de codes ISO 3166-1 alpha-2 en majuscules « configured for feed. Omitted/empty does not mean worldwide. Requires market setup. » Ainsi ["US"] est valide, ["United States"] ou ["us"] ne le sont pas. store_country est le pays de la boutique du vendeur sous forme de code ISO, pas une surcharge régionale de prix ou de stock.
Les règles de données qui s’appliquent à tous les champs
Ces conventions viennent de la section « general conventions » de la spécification et s’appliquent quel que soit le format de fichier.
- Omettez les valeurs inconnues. « Omit an unknown value. Unless a row says otherwise, an omitted field, JSON null, or an empty delimited cell supplies no value. »
- Aucune valeur de remplissage. « Do not use placeholder strings such as null, unknown, or n/a; unknown is valid only where explicitly listed. » Le seul endroit où
unknownest une valeur légale estavailability. - Booléens. « For boolean fields, use JSON true or false, or the lowercase strings true and false in delimited files. »
TRUE,1,yesetYne sont pas des booléens. - Décimales. Point décimal, aucun séparateur de milliers, aucune notation exponentielle.
- Identifiants sous forme de chaînes. « Keep identifiers as strings to preserve leading zeros. » Cela compte pour
gtin,item_id,offer_idetmpn, et surtout en Parquet, où un outil d’écriture qui déduit une colonne entière supprime les zéros. - Texte et URL. « Use UTF-8 text and absolute HTTP or HTTPS URLs; prefer HTTPS. »
- Guillemets en CSV. « In CSV, quote a cell containing commas, quotes, or newlines, and double each embedded quote. JSON objects in CSV or TSV cells must be serialized as JSON. » Un
variant_dictdans une cellule CSV ressemble à"{""color"":""Black"",""size"":""10""}". - Stabilité d’une mise à jour à l’autre. Gardez
item_id,group_idetoffer_idstables quand le prix, le stock, le titre ou les images changent.
Les alias hérités
Les anciens noms sont encore acceptés, mais la spécification demande de « Send only one name per value » et précise quel nom l’emporte quand les deux sont présents : « item_id wins over id and sku; group_id wins over item_group_id; the enable_ flags win over their is_eligible_ names. » Utilisez les noms actuels et n’émettez jamais l’alias dans le même fichier.
| Nom actuel | Alias hérité |
|---|---|
item_id | id, sku |
group_id | item_group_id |
is_eligible_search | enable_search |
is_eligible_checkout | enable_checkout |
is_ads_eligible | is_eligible_ads |
return_deadline_in_days | return_window |
Si votre flux dérive d’un export Google Shopping, ce sont les noms Google (id, link, image_link, item_group_id) qu’il faut convertir. La comparaison Flux Google Shopping ou flux OpenAI détaille cette correspondance.
Une ligne JSONL valide
Une ligne par article. Cette ligne utilise les champs obligatoires, les champs de variante et quelques champs recommandés et optionnels. Notez que le titre sépare les détails de variante par une virgule, et que chaque booléen est un booléen JSON, pas une chaîne.
{"item_id":"TRAIL-BLK-10","group_id":"TRAIL","listing_has_variations":true,"variant_dict":{"color":"Black","size":"10"},"offer_id":"northline-TRAIL-BLK-10","title":"Trail running shoes, black, size 10","description":"Waterproof trail shoes with a rubber outsole and mesh lining. Lace closure, 320 g per shoe.","url":"https://example.com/products/trail?color=black&size=10&utm_medium=feed","brand":"Northline","seller_name":"Northline Outdoor","image_url":"https://example.com/images/trail-black.jpg","additional_image_urls":["https://example.com/images/trail-black-side.jpg"],"availability":"in_stock","price":"79.99 USD","sale_price":"59.99 USD","gtin":"00012345678905","condition":"new","color":"Black","size":"10","product_category":"Apparel & Accessories > Shoes","is_eligible_search":true,"is_ads_eligible":true,"target_countries":["US"]}
Le paramètre utm_medium=feed sur url suit la page des bonnes pratiques, qui suggère d’ajouter « feed attribution parameters to url (for example utm_medium=feed) » afin de distinguer les clics venant du flux dans vos outils d’analyse. La même page demande un texte « concise, factual copy » dans les titres et les descriptions, et de garder « title, url, description, media, availability, and price variant-specific when those values differ ».
Erreurs fréquentes
- Exporter
priceetcurrencyen deux colonnes, ou avec une virgule décimale locale. - Copier
group_iddepuisitem_id, ce qui ne produit aucun groupe de variantes. - Écrire
TRUE/FALSEou1/0dans les colonnes booléennes. - Remplir
brandouseller_nameavecn/apour passer un contrôle « obligatoire » dans un outil interne ; la spécification traite cette valeur de remplissage comme invalide. - Laisser le HTML de l’éditeur de la boutique dans
description. - Envoyer
idetitem_iddans le même fichier. - Laisser un tableur convertir
gtinen nombre et supprimer le zéro initial. - Passer
is_eligible_checkout=truesur un produit dontis_eligible_searchvautfalse.
Comment Convrail valide chaque règle avant la livraison
Convrail applique ces règles avant qu’un fichier n’atteigne OpenAI, de sorte qu’une ligne cassée vous est signalée au lieu de disparaître :
- Les 9 champs obligatoires sont contrôlés en présence et en format sur chaque ligne : la monnaie en
amount CURRENCY,availabilityface à la liste fermée,urletimage_urlcomme URL HTTP ou HTTPS absolues pointant vers un JPEG ou un PNG direct. Convrail plafonne aussiitem_idà 100 caractères etbrand,seller_nameetmpnà 70, et rejette les titres écrits entièrement en majuscules. - Les valeurs de remplissage (
null,unknown,n/a) dansbrandetseller_namesont rejetées. - Les champs conditionnels sont validés quand ils sont présents :
sale_pricestrictement inférieur àpricedans la même devise,group_iddifférent deitem_id,is_eligible_checkoutexigeant l’éligibilité à la recherche plus les deux URL de politique,target_countriesen codes alpha-2 majuscules,star_ratingentre 0 et 5. - La clé de contrôle du GTIN est vérifiée. Un GTIN invalide est omis plutôt qu’envoyé, la ligne reste donc valide ; l’omission est consignée dans le journal.
- Le HTML est retiré des descriptions, et les booléens sont émis comme booléens JSON en JSONL et en Parquet, et comme chaînes en minuscules en CSV et en TSV.
- Chaque rejet est enregistré avec l’
item_id, le champ et la règle, dans un journal d’exécution qui compte aussi les articles lus, acceptés et rejetés.
Le même catalogue peut aussi être projeté en flux compatible Google. Si vos produits manquent déjà dans les résultats de ChatGPT, Pourquoi vos produits n’apparaissent pas dans les résultats shopping de ChatGPT relie chaque symptôme à une règle ci-dessus, et Parquet, JSONL ou CSV couvre les choix au niveau du fichier.
Prochaine étape
Connectez votre boutique et laissez Convrail valider votre catalogue face à chaque règle de cette page avant la première livraison : voir la page flux produit.
Sources
Questions fréquentes
Combien de champs sont obligatoires dans le flux produit OpenAI ?
Neuf : item_id, title, description, url, brand, seller_name, image_url, availability et price. Une ligne à laquelle il manque l'un d'eux, ou qui porte une valeur mal formée dans l'un d'eux, est inutilisable.
Comment écrire le prix dans un flux produit OpenAI ?
Le montant, une espace, puis le code ISO 4217 en majuscules, par exemple 79.99 USD. Point décimal, aucun séparateur de milliers, aucun symbole monétaire, et pas plus de décimales que la devise n'en autorise.
OpenAI accepte-t-il encore id, sku ou item_group_id ?
Oui, comme alias hérités de item_id et group_id, mais la spécification demande de n'envoyer qu'un seul nom par valeur. Utilisez les noms actuels dans tout nouveau flux et ne mélangez jamais les deux dans le même fichier.
sale_price peut-il être égal à price ?
Non. La spécification exige un sale_price supérieur à zéro, strictement inférieur à price et dans la même devise ; un prix promotionnel égal, supérieur, nul, négatif ou dans une autre devise n'est pas utilisé.
Que se passe-t-il si group_id est identique à item_id ?
Aucun groupe de variantes n'est créé. group_id doit être un identifiant stable de fiche parente, partagé par toutes les variantes et différent de chaque item_id, avec listing_has_variations à true sur chaque ligne de variante.