One real-world item, independent of who sells it. Everything else in the API hangs off this. A product is not a listing — four sellers carrying the same headphones produce one Product and four Listings.
| Field | Type | Notes |
|---|---|---|
| product_id ·always | string | Stable. Safe as your foreign key. |
| gtin | string | null | GTIN-14, zero-padded, check digit verified. Null in categories that publish none — apparel and jewellery are near-zero. |
| mpn | string | null | Manufacturer part number. More reliable than GTIN in industrial and auto. |
| brand | string | null | Normalised. Note: a storefront's own vendor field is frequently NOT the brand — we observed 'Galaxy S25 FE Series' as vendor on a Spigen case. Brand here is resolved, not copied. |
| title ·always | string | Canonical, not any single seller's phrasing. |
| category ·always | string | Dotted taxonomy path, mapped from every seller's own tree. |
| attributes | object | Category-specific and structured. See the Attribute object. |
| media | Media[] | Images and video. Median 5 per product across our sample; electronics runs to 18. |
| variant_axes | string[] | Which attributes vary — Size, Colour, Material, Device. Derived, not declared. |
| variants ·always | int | Count of variant products beneath this one. |
| sellers ·always | int | How many sellers currently list it. |
| description | string | null | Normalised plain text. Present on ~90% of real catalogue rows. |
{
"product_id": "prd_8Fk2xQ",
"gtin": "00885909950805",
"mpn": "WH1000XM5/B",
"brand": "Sony",
"title": "Sony WH-1000XM5 Wireless Noise Cancelling Headphones",
"category": "electronics.audio.headphones",
"attributes": {
"form_factor": "over-ear",
"anc": true,
"battery_hours": 30,
"foldable": false,
"connectivity": ["bluetooth-5.2", "usb-c", "3.5mm"]
},
"variant_axes": ["colour"],
"variants": 3,
"sellers": 4,
"media": [ { "role": "primary", "url": "https://…/xm5-black-1600x.jpg" } ]
}Storefront catalogues put anything in the vendor field. We measured it holding a device-compatibility string rather than a manufacturer. Copying it straight through would split one brand across dozens of phantom vendors and destroy brand-level analysis.
Electronics and grocery are near-universal. Apparel, jewellery and DTC brands are close to zero — public storefront catalogues strip the barcode field entirely. Design any integration to work without a GTIN, because in half of commerce there is not one.
Sellers declare option names inconsistently — Size, size, Sizes, Length. The axes here are normalised across sellers, which is what makes a cross-seller facet possible at all.