SKUHelm

Validate a product feed

How to validate a product feed and fix the usual errors

A practical way to check an OpenAI product feed before you send it, with the most common errors, what causes them and how to fix each one.

Checked against the sources on 7 October 20267 min read

Most feeds fail for dull reasons. A currency symbol in a price. An image link that needs a login. The same ID used twice. None of it is hard to fix once you can see it. The trouble is seeing it across a few hundred rows.

This guide shows how to check a feed in a sensible order and what the common errors mean.

Check in this order

  1. File level. Is it UTF-8? Is it the right format, with one JSON record per line for JSONL? OpenAI's spec says JSON, XML, RSS, Atom and spreadsheets are not supported.
  2. Required fields. Does every row have all nine: item_id, title, description, url, brand, seller_name, image_url, availability, price?
  3. Formats. Is the price written as amount plus currency code? Is availability one of the five allowed values?
  4. Limits. Titles at 150 characters or fewer, descriptions at 5,000 or fewer.
  5. Identity. Are IDs unique? Are barcodes valid?
  6. Links. Do product and image URLs open for someone who is not logged in?
  7. Variants. Do variant rows share a group_id and carry the full set of variant fields?
  8. Meaning. Does the title match the image? Does the price match the page?

Steps one to five can be checked by a machine. Steps six and seven can be checked by a machine that makes web requests. Step eight needs your eyes, so look at a sample of rows yourself.

The common errors

Missing seller_name or brand

These fail on every row at once because shop exports do not include a seller name and often lack a brand. Fix it once, at store level, not row by row. The spec rejects placeholders such as n/a or null.

Price in the wrong shape

The spec wants a number, a space and an uppercase currency code, like 24.00 GBP. Common mistakes: a pound sign, a thousands comma, a missing currency, or a price in minor units. WooCommerce's API, for example, gives 2400 for a price of 24.00. Divide it by 100 for a currency with two decimal places.

Sale price not below price

sale_price must be above zero, below price, and in the same currency. This goes wrong when a platform stores the current price and the old price the other way round. Shopify, for one, keeps the old price in compare_at_price. The feed wants the old price in price and the new one in sale_price.

Availability free text

Only in_stock, out_of_stock, pre_order, backorder and unknown are allowed. A spreadsheet column that says Yes or Sold out has to be translated. Use pre_order for something offered before release and backorder for something temporarily awaiting stock.

Image links that fail

The image has to be a direct link to a JPEG or PNG that anyone can open. Links to a web page that contains the image, links behind a login, and links that expire after a few hours all fail. WebP-only images are a frequent surprise.

Duplicate or unstable IDs

item_id has to be unique, and it has to stay the same for the same product. OpenAI's upload guide says it matches products by item_id, not by file name. An ID built from a title changes when you edit the title, and the product then looks new.

Description full of HTML

The spec asks for factual plain text. Strip tags, and avoid lines like Buy now or free delivery. Facts about the product belong here. Offers belong in price and shipping fields.

Bad GTINs

A GTIN is 8, 12, 13 or 14 digits and the last digit is a check digit. Spreadsheets drop leading zeros, which breaks it. A wrong barcode is worse than none. If you are not sure, leave the field out.

Fixing once versus fixing every row

Group the errors by cause before you start. If 400 rows say seller_name is missing, that is one problem. If 12 rows have an image that fails, those are twelve small ones. The first kind belongs in a store setting. The second kind belongs in your shop admin, where you fix the product itself so the next sync stays fixed.

Edit at the source. If you patch the exported file and leave the shop as it was, the same errors come back the next time you export.

A feed that passes is not an approved feed

A clean validation means the file matches the spec. It does not mean OpenAI has accepted you as a merchant. Onboarding is currently open to approved partners only, according to their documentation.

A small routine that works

Validate before you send, every time, even if you only changed one price. Keep the previous version of the file so you can compare. Read ten rows by hand after each big change: pick a cheap item, an expensive one, a variant, one with a sale price and one out of stock. If those five look right, the rest usually do.

When something fails, resist the urge to patch the file by hand. Find the field in the shop that produced it and fix it there. A hand edit disappears at the next sync, and then the same error is back with no one remembering why.

Paste your shop address or upload a CSV and get every error grouped by cause.

Validate my feed

Questions

What does SKUHelm check?

Every row against the field rules in OpenAI's spec, such as required fields, formats, limits, allowed values, ID uniqueness and variant structure.

Does it check that my image links work?

Test a few in a private browser window yourself. An image that opens for you while you are logged in may not open for anyone else.

How often should I validate?

Every time the feed changes. On Pro, every hourly sync is checked, and you get an email if items drop out of the feed.

Why does one product give several rows?

Each variant is its own row in the spec, with its own ID, price and availability.

Sources