Translations
Translation management for storefront text and multi-language support
Get system default translations
Returns system default translations only (no merchant overrides).
Use this to compare against GET /translations and identify which values are merchant customizations vs system defaults.
Important: Also use this endpoint to look up the correct translation key before calling PUT.
Many keys have internal prefixes (e.g., [[WidgetV2]], [[Checkout]]) that differ from the displayed UI text.
Search by value (not key) in the response to find the exact key to use in PUT requests.
200System default translations for all supported locales
trueSystem translations keyed by locale code
Additional metadata such as counts and pagination
"Operation completed successfully""2023-07-28T07:27:54.123Z"GET /rest_api/v2/translations/defaults HTTP/1.1Host: dev-api.joy.soX-Joy-Loyalty-App-Key: YOUR_API_KEYX-Joy-Loyalty-Secret-Key: YOUR_API_KEYAccept: */*
{"success": true,"data": {},"meta": {},"message": "Operation completed successfully","timestamp": "2023-07-28T07:27:54.123Z"}
Get all translations
Returns translation config and text for ALL languages (primary + additional), merged with system defaults. Each language contains ~300+ translation key-value pairs.
Response includes config fields (primaryLanguage, detectMethod, additionalLanguages, embedContent) and dynamic language objects (en, fr, de, etc.) with translation key-value pairs.
200Full translation config and text
trueFull translation object containing config and text for all languages. Language keys (en, fr, de...) are dynamic objects with translation key-value pairs. Mirrors the internal admin translation system.
{"primaryLanguage":"en","detectMethod":"browserLanguage","additionalLanguages":[{"code":"fr","active":true}],"embedContent":["en","fr"],"en":{"Join Program":"Join Program","Redeem":"Redeem","Ways to earn":"Ways to earn"},"fr":{"Join Program":"Rejoindre le programme","Redeem":"Échanger","Ways to earn":"Façons de gagner"}}Show properties
Primary language code
"en"How to detect customer language:
- customerIp: By IP geolocation
- browserLanguage: By browser language setting
- optionalStorefrontLanguage: Use Shopify storefront language
"browserLanguage"Additional languages with active status
Show properties
Language code
"fr"Whether language is active for customers
trueLanguages for embedded content (FAQs, exclusive products)
["en","fr"]Additional metadata such as counts and pagination
"Operation completed successfully""2023-07-28T07:27:54.123Z"GET /rest_api/v2/translations HTTP/1.1Host: dev-api.joy.soX-Joy-Loyalty-App-Key: YOUR_API_KEYX-Joy-Loyalty-Secret-Key: YOUR_API_KEYAccept: */*
{"success": true,"data": {"primaryLanguage": "en","detectMethod": "browserLanguage","additionalLanguages": [{"code": "fr","active": true}],"embedContent": ["en","fr"],"en": {"Join Program": "Join Program","Redeem": "Redeem","Ways to earn": "Ways to earn"},"fr": {"Join Program": "Rejoindre le programme","Redeem": "Échanger","Ways to earn": "Façons de gagner"}},"meta": {},"message": "Operation completed successfully","timestamp": "2023-07-28T07:27:54.123Z"}
Update translations
Updates translation config and text. Send the full translation object from the GET response with modifications applied (not partial updates).
⚠️ Key Lookup Warning:
Translation keys are NOT always the same as the displayed UI text.
Many keys have internal prefixes such as [[WidgetV2]], [[Checkout]], [[POS]], etc.
Example:
- UI text:
Ways to earn - Actual key:
[[WidgetV2]]Ways to earn
Before calling PUT to update a specific text:
- ALWAYS call
GET /translations/defaultsfirst - Search by VALUE (not key) to find the correct key — filter entries where value matches the target text
- Use the exact key found in step 2 for the PUT request
Sending a PUT with a non-existent key will return success: true but will have no visible effect on the storefront.
Workflow: GET /translations/defaults → find correct key by value → GET /translations → modify keys → PUT /translations with entire object.
Behavior:
- Diffs request vs system defaults — only stores overrides in Firestore
- If primaryLanguage or its content changed — auto-translates ALL additional languages via Google Translate API
- If embedContent changed — triggers background jobs for FAQs and exclusive products
- Publishes metafield sync to Shopify
Idempotent: GET → PUT unchanged = no side effects (diff produces empty result).
CRITICAL — PUT REPLACES, does NOT merge: Sending only a subset of keys will DELETE all other existing merchant customizations. You MUST send the complete object from GET with your modifications applied.
Data loss example:
- Existing customs:
{en: {"A": "custom A", "B": "custom B"}} - PUT with:
{en: {"C": "custom C"}}(partial) - Result:
{en: {"C": "custom C"}}— A and B are permanently lost
Correct workflow:
GET /translations— get current full state (all keys)GET /translations/defaults— get system defaults- Find the correct key by searching defaults by VALUE
- Modify the key in the full GET response
PUT /translations— send the entire modified object back
Primary language code
"en"How to detect customer language:
- customerIp: By IP geolocation
- browserLanguage: By browser language setting
- optionalStorefrontLanguage: Use Shopify storefront language
"browserLanguage"Additional languages with active status
Show properties
Language code
"fr"Whether language is active for customers
trueLanguages for embedded content (FAQs, exclusive products)
["en","fr"]200Save succeeded
trueShow properties
trueAdditional metadata such as counts and pagination
"Operation completed successfully""2023-07-28T07:27:54.123Z"500Firestore save failed (e.g., undefined values in data)
falseShow properties
"Resource not found""NOT_FOUND"404"2023-07-28T07:27:54.123Z"PUT /rest_api/v2/translations HTTP/1.1Host: dev-api.joy.soX-Joy-Loyalty-App-Key: YOUR_API_KEYX-Joy-Loyalty-Secret-Key: YOUR_API_KEYContent-Type: application/jsonAccept: */*Content-Length: 66{"primaryLanguage": "en","detectMethod": "browserLanguage"}
{"success": true,"data": {"updated": true},"meta": {},"message": "Operation completed successfully","timestamp": "2023-07-28T07:27:54.123Z"}
Add a new language
Adds a new language and auto-translates all text (~300+ keys) from the primary language using Google Translate API. Also auto-translates program titles and milestone descriptions.
Returns the full translation object with the new language included.
Source language code to translate from
"en"Target language code to add
"fr"201Language added with auto-translated text
trueFull translation object containing config and text for all languages. Language keys (en, fr, de...) are dynamic objects with translation key-value pairs. Mirrors the internal admin translation system.
{"primaryLanguage":"en","detectMethod":"browserLanguage","additionalLanguages":[{"code":"fr","active":true}],"embedContent":["en","fr"],"en":{"Join Program":"Join Program","Redeem":"Redeem","Ways to earn":"Ways to earn"},"fr":{"Join Program":"Rejoindre le programme","Redeem":"Échanger","Ways to earn":"Façons de gagner"}}Show properties
Primary language code
"en"How to detect customer language:
- customerIp: By IP geolocation
- browserLanguage: By browser language setting
- optionalStorefrontLanguage: Use Shopify storefront language
"browserLanguage"Additional languages with active status
Show properties
Language code
"fr"Whether language is active for customers
trueLanguages for embedded content (FAQs, exclusive products)
["en","fr"]Additional metadata such as counts and pagination
"Operation completed successfully""2023-07-28T07:27:54.123Z"400Invalid or unsupported locale
falseShow properties
"Resource not found""NOT_FOUND"404"2023-07-28T07:27:54.123Z"POST /rest_api/v2/translations/languages HTTP/1.1Host: dev-api.joy.soX-Joy-Loyalty-App-Key: YOUR_API_KEYX-Joy-Loyalty-Secret-Key: YOUR_API_KEYContent-Type: application/jsonAccept: */*Content-Length: 59{"primaryLanguage": "en","additionalLanguage": "fr"}
{"success": true,"data": {"primaryLanguage": "en","detectMethod": "browserLanguage","additionalLanguages": [{"code": "fr","active": true}],"embedContent": ["en","fr"],"en": {"Join Program": "Join Program","Redeem": "Redeem","Ways to earn": "Ways to earn"},"fr": {"Join Program": "Rejoindre le programme","Redeem": "Échanger","Ways to earn": "Façons de gagner"}},"meta": {},"message": "Operation completed successfully","timestamp": "2023-07-28T07:27:54.123Z"}
Remove a language
Removes a language. Clears all translation data for that locale and removes it from the additionalLanguages array. Publishes metafield sync after removal.
Language code to remove
200Language removed
true404No translation document found for shop
falseShow properties
"Resource not found""NOT_FOUND"404"2023-07-28T07:27:54.123Z"DELETE /rest_api/v2/translations/languages/{locale} HTTP/1.1Host: dev-api.joy.soX-Joy-Loyalty-App-Key: YOUR_API_KEYX-Joy-Loyalty-Secret-Key: YOUR_API_KEYAccept: */*
{"success": true}
Update FAQ translations
Updates FAQ translations separately from main translations. Each language has an array of FAQ items (title, content, orderBy). Triggers a background job to process FAQ translation updates and sync to Shopify metafields.
FAQ translations keyed by language code
{"en":[{"title":"How does it work?","content":"Earn points on every purchase...","orderBy":0}],"fr":[{"title":"Comment ça marche?","content":"Gagnez des points à chaque achat...","orderBy":0}]}200FAQ translations updated
true400Missing translateFaqs field
falseShow properties
"Resource not found""NOT_FOUND"404"2023-07-28T07:27:54.123Z"PUT /rest_api/v2/translations/faqs HTTP/1.1Host: dev-api.joy.soX-Joy-Loyalty-App-Key: YOUR_API_KEYX-Joy-Loyalty-Secret-Key: YOUR_API_KEYContent-Type: application/jsonAccept: */*Content-Length: 331{"translateFaqs": {"en": [{"title": "How does it work?","content": "Earn points on every purchase...","orderBy": 0}],"fr": [{"title": "Comment ça marche?","content": "Gagnez des points à chaque achat...","orderBy": 0}]}}
{"success": true}