Manage storefront and content translations
/admin/api/translations
List all translation keys (built-in and custom) with their default and override values per locale, with pagination and filtering.
/admin/api/translations
Bulk upsert custom translation overrides. Each entry specifies a key, locale, and value. An empty value deletes the override (reverts to built-in default). Custom keys not in the built-in set are also supported.
/admin/api/translations/{key}/{locale}
Delete a single custom translation override, reverting to the built-in default for that key and locale.
/admin/api/content-translations
Replace all content translations for a catalogue entity. Supports entity types: product, category, option, option_value. Translatable fields depend on the entity type (e.g. name, description for products). An empty translations array clears all translations for that entity.
/admin/api/translations
List all translation keys (built-in and custom) with their default and override values per locale, with pagination and filtering.
| Name | Type | Required | Description |
|---|---|---|---|
| page | integer | optional | Page number, 1-indexed (default: 1) |
| per_page | integer | optional | Items per page, 1-100 (default: 20) |
| search | string | optional | Case-insensitive text search on key name |
| key_type | string | optional | Filter by type: "builtin" or "custom" |
{
"data": [
{
"key": "product_add_to_cart",
"is_builtin": true,
"defaults": {
"en": "Add to cart",
"de": "In den Warenkorb"
},
"custom": {
"en": "Buy now"
}
},
{
"key": "home_custom_banner",
"is_builtin": false,
"defaults": {},
"custom": {
"en": "Free shipping on orders over $50",
"de": "Kostenloser Versand ab 50 EUR"
}
}
],
"page": 1,
"per_page": 20,
"total": 85,
"total_pages": 5,
"locales": [
"en",
"de"
]
}
curl "https://yourshop.zeroshop.io/admin/api/translations?page=1&per_page=20&search=cart" \
-H "Authorization: Bearer zspat_..."
import requests
resp = requests.get(
"https://yourshop.zeroshop.io/admin/api/translations",
params={"page": 1, "per_page": 20, "search": "cart"},
headers={"Authorization": "Bearer zspat_..."}
)
translations = resp.json()
const params = new URLSearchParams({ page: 1, per_page: 20, search: "cart" });
const resp = await fetch(
`https://yourshop.zeroshop.io/admin/api/translations?${params}`,
{ headers: { "Authorization": "Bearer zspat_..." } }
);
const data = await resp.json();
require "net/http"
require "json"
uri = URI("https://yourshop.zeroshop.io/admin/api/translations?page=1&per_page=20&search=cart")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer zspat_..."
resp = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(resp.body)
/admin/api/translations
Bulk upsert custom translation overrides. Each entry specifies a key, locale, and value. An empty value deletes the override (reverts to built-in default). Custom keys not in the built-in set are also supported.
{
"translations": [
{
"key": "product_add_to_cart",
"locale": "en",
"value": "Buy now"
},
{
"key": "product_add_to_cart",
"locale": "de",
"value": "Jetzt kaufen"
},
{
"key": "home_custom_banner",
"locale": "en",
"value": "Free shipping on orders over $50"
}
]
}
curl -X PUT "https://yourshop.zeroshop.io/admin/api/translations" \
-H "Authorization: Bearer zspat_..." \
-H "Content-Type: application/json" \
-d '{
"translations": [
{"key": "product_add_to_cart", "locale": "en", "value": "Buy now"},
{"key": "product_add_to_cart", "locale": "de", "value": "Jetzt kaufen"}
]
}'
import requests
resp = requests.put(
"https://yourshop.zeroshop.io/admin/api/translations",
headers={"Authorization": "Bearer zspat_..."},
json={
"translations": [
{"key": "product_add_to_cart", "locale": "en", "value": "Buy now"},
{"key": "product_add_to_cart", "locale": "de", "value": "Jetzt kaufen"}
]
}
)
assert resp.status_code == 204
const resp = await fetch("https://yourshop.zeroshop.io/admin/api/translations", {
method: "PUT",
headers: {
"Authorization": "Bearer zspat_...",
"Content-Type": "application/json"
},
body: JSON.stringify({
translations: [
{ key: "product_add_to_cart", locale: "en", value: "Buy now" },
{ key: "product_add_to_cart", locale: "de", value: "Jetzt kaufen" }
]
})
});
require "net/http"
require "json"
uri = URI("https://yourshop.zeroshop.io/admin/api/translations")
req = Net::HTTP::Put.new(uri)
req["Authorization"] = "Bearer zspat_..."
req["Content-Type"] = "application/json"
req.body = {
translations: [
{ key: "product_add_to_cart", locale: "en", value: "Buy now" },
{ key: "product_add_to_cart", locale: "de", value: "Jetzt kaufen" }
]
}.to_json
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
/admin/api/translations/{key}/{locale}
Delete a single custom translation override, reverting to the built-in default for that key and locale.
curl -X DELETE "https://yourshop.zeroshop.io/admin/api/translations/product_add_to_cart/en" \
-H "Authorization: Bearer zspat_..."
import requests
resp = requests.delete(
"https://yourshop.zeroshop.io/admin/api/translations/product_add_to_cart/en",
headers={"Authorization": "Bearer zspat_..."}
)
assert resp.status_code == 204
const resp = await fetch("https://yourshop.zeroshop.io/admin/api/translations/product_add_to_cart/en", {
method: "DELETE",
headers: { "Authorization": "Bearer zspat_..." }
});
require "net/http"
uri = URI("https://yourshop.zeroshop.io/admin/api/translations/product_add_to_cart/en")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer zspat_..."
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
/admin/api/content-translations
Replace all content translations for a catalogue entity. Supports entity types: product, category, option, option_value. Translatable fields depend on the entity type (e.g. name, description for products). An empty translations array clears all translations for that entity.
{
"entity_type": "product",
"entity_id": 1,
"translations": [
{
"locale": "de",
"field": "name",
"value": "Klassisches Baumwoll-T-Shirt"
},
{
"locale": "de",
"field": "description",
"value": "Ein bequemes T-Shirt aus 100% Baumwolle."
},
{
"locale": "fr",
"field": "name",
"value": "T-shirt classique en coton"
}
]
}
curl -X PUT "https://yourshop.zeroshop.io/admin/api/content-translations" \
-H "Authorization: Bearer zspat_..." \
-H "Content-Type: application/json" \
-d '{
"entity_type": "product",
"entity_id": 1,
"translations": [
{"locale": "de", "field": "name", "value": "Klassisches Baumwoll-T-Shirt"},
{"locale": "de", "field": "description", "value": "Ein bequemes T-Shirt aus 100% Baumwolle."}
]
}'
import requests
resp = requests.put(
"https://yourshop.zeroshop.io/admin/api/content-translations",
headers={"Authorization": "Bearer zspat_..."},
json={
"entity_type": "product",
"entity_id": 1,
"translations": [
{"locale": "de", "field": "name", "value": "Klassisches Baumwoll-T-Shirt"},
{"locale": "de", "field": "description", "value": "Ein bequemes T-Shirt aus 100% Baumwolle."}
]
}
)
assert resp.status_code == 204
const resp = await fetch("https://yourshop.zeroshop.io/admin/api/content-translations", {
method: "PUT",
headers: {
"Authorization": "Bearer zspat_...",
"Content-Type": "application/json"
},
body: JSON.stringify({
entity_type: "product",
entity_id: 1,
translations: [
{ locale: "de", field: "name", value: "Klassisches Baumwoll-T-Shirt" },
{ locale: "de", field: "description", value: "Ein bequemes T-Shirt aus 100% Baumwolle." }
]
})
});
require "net/http"
require "json"
uri = URI("https://yourshop.zeroshop.io/admin/api/content-translations")
req = Net::HTTP::Put.new(uri)
req["Authorization"] = "Bearer zspat_..."
req["Content-Type"] = "application/json"
req.body = {
entity_type: "product",
entity_id: 1,
translations: [
{ locale: "de", field: "name", value: "Klassisches Baumwoll-T-Shirt" },
{ locale: "de", field: "description", value: "Ein bequemes T-Shirt aus 100% Baumwolle." }
]
}.to_json
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
We value your privacy
We use cookies for essential site functionality and, with your consent, analytics to understand how our platform is used. No personal data is shared with third parties. See our Privacy Policy for details.