nt_01ABC) translated to French. Set COURIER_API_KEY to a key from your API keys page before you start. For sending with locales, TMS webhooks, and the full endpoint reference, see Localization.
Fetch translatable content
CallGET /notifications/{id}/content to get every element you can translate:
channel and group elements hold their children in their own elements array:
Save the
id of each element you want to translate, at whatever depth it sits.
Add ?version=draft to read the draft instead of the published content.
If your response comes back with blocks and channels rather than elements, that template predates the element model and the rest of this tutorial won’t apply to it.
Set a locale
One request per locale. Name each element byid and set the property that matches its type: content for text, title for meta.
id, flat in the elements array. You do not mirror the tree structure in the request.
You get back 200 with the new checksums and the state the write landed on:
/locales/de_DE. Locales are independent, so it leaves French untouched.
You can also send a partial update. The merge is one level deep: fields inside a locale merge, and each field’s value is then replaced wholesale. So sending only content for an element that also has an href translation leaves the href alone. The one exception is elements, which replaces that locale’s whole subtree, so send it complete. See how merging works.
Keep variable expressions such as {{data.name}} byte-identical to the default content. Courier substitutes them at send time, and an altered expression will not resolve.
Every override has to reference an element that already exists in the default content. One bad id fails the entire request with a 400 and writes nothing, so the valid overrides in the same array do not apply either. The error lists every bad id at once, so you can fix them all in one pass.
Draft vs published
Writes carry astate field instead of using a separate path:
The request above omitted
state, so it saved to the draft. Publish it:
"state": "PUBLISHED" with the locale write does both steps at once.
Note that PUBLISHED publishes the entire draft, not only your translation, so any other unpublished edits on that template go live with it.
Keep translations in sync
checksum is how you find translations that have gone stale. Store the element’s checksum when you translate it, then compare on the next fetch. If an element’s checksum changed, its default content changed and the translation behind it needs revisiting.
When the default content is what changed, update the element itself. PUT /elements/{elementId} is a full replace, so pass the translations you want to keep in the same request: