title, description, and image_url in more than one language. You translate inline on the resource’s own create and update: there is no separate translations endpoint and no translations object in the payload. The lang query parameter selects the locale a request reads or writes.
This guide covers the model that applies to all eight resources, then works through Products end to end.
The model
Six rules govern every translation, whatever the resource:- Create writes the default locale.
POST /api/v202604/company/{resource}always writes the store’s default locale and keeps its full payload — whateverlangsays. A resource created under a translation would read back blank in the store’s own language, solangis validated on create but does not select the write locale. - You translate an existing row with PATCH. Send
PATCH /api/v202604/company/{resource}/{id}?lang=<iso>against a row that already exists. Thelangyou pass is the locale you write. - A translation PATCH is text only. Against any locale other than the store’s default, only the translated fields (
title,description,image_url) are written. The slug, lifecycle, country availability, metafields, SEO, and associations in the same payload are ignored, so translating a title can never regenerate the slug or move the status. Send those in a request against the store’s default locale instead. - An unsold locale returns
422. Alangthe store does not sell in is rejected — translations are never written to a locale the store has not enabled. Add the language to the store first. - Public reads fall back. On the public surface, any field with no translation in the requested locale falls back to its default-locale value, so a partially translated resource never renders blank.
languageslists what is translated. Every response carries alanguagesarray listing exactly the locales that carry a translation, always including the store’s default.
lang=fr as its default write, not a translation.
The typical flow is: create the resource in the default locale, then send one PATCH per additional locale carrying only the translated text.
Translate a product
Start by creating the product in the store’s default locale. This is an ordinary create — the full payload is kept.id (say 60311) and a languages array that already lists the default locale.
Now add a French translation to that existing product. Pass lang=fr and send only the translated text — the title and description in French.
fr joins the product’s languages array.
To read a specific translation back before editing it, pass lang on the company show endpoint:
422.
Read versus write
Reading a locale and writing one are different operations — this is where translating media trips people up. On a GET,lang only renders an existing translation, and filter[language] only filters the catalog to rows already translated in a locale. Neither writes anything. A media item renders in French on the public catalog:
lang=fr, exactly as you did for a product:
Every translatable resource
All eight storefront resources translate the same way. Each carriestitle, description, and image_url as translated fields; send lang and only the translated text on the company update endpoint, wrapped under the resource’s own body key.
The body key is the only thing that changes between resources — playlists wrap their write in
library, media in medium, and enrollment packs in enrollment_pack, matching each resource’s create contract.
Next steps
- Control country availability — a per-row country list, written on the store’s default locale (not through a translation PATCH).
- Rename, publish, and schedule — the lifecycle and slug fields a translation PATCH deliberately leaves untouched.