Two fields are load-bearing for a sync
sku is the stable upsert key — match on it so re-runs update rather than duplicate. slug is the public URL; once a product is live, keep its slug stable. Prices aren't stored as blanks — read the Pricing model before mapping them.
Product images arrive by feed, not upload
API-delivered images use primaryImageUrl, galleryUrls and feedGroupId (which links feed photos and is not 1:1 with SKU). The images array is for assets uploaded by hand — a separate path.
Pricing model
Rather than one row per product-and-region (which would explode the catalogue), pricing is pivoted into a regionalPricing[] array — one regionalPrice row per region, holding a buy and a hire figure. Each mode carries a state instead of a blank, so the site knows how to render it:
Every row keys to one of the 15 regions by regionSlug (Grafton and Lismore are NSW; the rest QLD):
Controlled vocabularies
Fields that only accept specific values — send them exactly (case-sensitive).
Machine-readable contract
The same schema as JSON — hand this to the developer building the sync. It's also saved in the repo at docs/catalogue-schema.json.