Message template translations

Translate SMS and WhatsApp templates through the Store API.

Translate the content of an SMS or WhatsApp template (one message type and channel, addressed by the id that List message templates returns) for an enabled non-default store locale. Reads require read_marketing and read_translations; writes require write_marketing and write_translations. A customer whose language has a translation receives it; every other customer receives the template's own text.

A translation keeps the original's values and tags exactly ({{ order.number }}, {% if ... %}): only the words around them change. One that changes, adds or drops a value or tag is refused with MARKETING_TRANSLATION_VARIABLES_MISMATCH, and details.variables lists what to keep. Blank text is refused with MESSAGE_TEMPLATE_CONTENT_REQUIRED and text over the template's max_content_length with MESSAGE_TEMPLATE_CONTENT_TOO_LONG. An empty string clears a translation. Editing or resetting the original reports its translations outdated (is_outdated: true) until they are updated. Store Admin, the Tringify mobile app, translation CSV (message_template), AI translation and MCP write the same translations, and each change sends message_templates/translations/update, or message_templates/translations/delete when a translation is cleared, like every translatable resource. message_templates/update is sent only when the template's own text is edited or reset.

Batch get message template translations

GET read_marketing + read_translations

Fetch message template translations in batch.

A message template is one SMS or WhatsApp text: one message type and channel, addressed here by the id that List message templates and Get a message template return. Its content translates per store language; a customer whose language has a translation receives it, every other customer the template's own text. A translation keeps the original's values and tags exactly ({{ ... }} and {% ... %}, in any order within the same block): only the text around them changes, and one that does not is refused with MARKETING_TRANSLATION_VARIABLES_MISMATCH and details.variables listing what to keep. It must not be blank (MESSAGE_TEMPLATE_CONTENT_REQUIRED) and holds at most the template's max_content_length characters (MESSAGE_TEMPLATE_CONTENT_TOO_LONG). A translation written against an earlier original is reported outdated. Store Admin, the Tringify mobile app, translation CSV (resource message_template), AI translation and MCP translate the same texts. Each change sends message_templates/translations/update, or message_templates/translations/delete when a translation is cleared. Returns a resources entry keyed by message_template:{id} for each requested template (at most 100 per call); a template without a translation has an empty object. Fields without a translation in this locale are omitted from the response. An omitted field is not empty: shoppers see the store's base-language value, which the resource's own GET endpoint returns.

Path parameters

Name Type Description
locale required string

Enabled non-default store locale.

Example: fr

Query parameters

Name Type Description
ids required string

Comma-separated message template IDs.

Example: 0b6f1e2d-8c4a-4f3b-9e7d-2a1c5b8d9e04,5c2d7a9e-1b3f-4e6d-8a0c-9f2e4b6d8a13

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 TRANSLATION_LOCALE_NOT_ENABLED

    Locale is not enabled for this store.

  • 400 TRANSLATION_DEFAULT_LOCALE_FORBIDDEN

    Translations cannot target the store's default locale, the language of the template's own text.

  • 400 TRANSLATION_RESOURCE_ID_REQUIRED

    At least one template ID is required.

  • 400 TRANSLATION_INVALID_RESOURCE_ID

    A template ID is not a UUID.

  • 400 TRANSLATION_RESOURCE_ID_NOT_IN_STORE

    A template does not exist in this store.

  • 400 TRANSLATION_TOO_MANY_RESOURCES

    The request exceeds the translation batch resource limit.

Batch set message template translations

PUT write_marketing + write_translations

Set template translations for any languages in one call.

A message template is one SMS or WhatsApp text: one message type and channel, addressed here by the id that List message templates and Get a message template return. Its content translates per store language; a customer whose language has a translation receives it, every other customer the template's own text. A translation keeps the original's values and tags exactly ({{ ... }} and {% ... %}, in any order within the same block): only the text around them changes, and one that does not is refused with MARKETING_TRANSLATION_VARIABLES_MISMATCH and details.variables listing what to keep. It must not be blank (MESSAGE_TEMPLATE_CONTENT_REQUIRED) and holds at most the template's max_content_length characters (MESSAGE_TEMPLATE_CONTENT_TOO_LONG). A translation written against an earlier original is reported outdated. Store Admin, the Tringify mobile app, translation CSV (resource message_template), AI translation and MCP translate the same texts. Each change sends message_templates/translations/update, or message_templates/translations/delete when a translation is cleared. Each row is one template in one language: id, locale (any enabled non-default store locale) and fields. Rows for several languages can be mixed in one call; send at most 100 rows (one row = one template in one locale) and at most one row per template and locale. Each row is saved on its own: a failing row never stops the others. Empty values clear the matching field translation; omitted fields keep their translation. Every row is validated exactly like the single translation endpoint. The response has totals (rows, saved, failed) and one results entry per row in request order: {id, locale, status} with status saved or failed. A failed row carries the full error (code, message, details); its codes are the single endpoint's codes plus TRANSLATION_ROW_DUPLICATE. A saved rich-text row whose unsafe markup was removed lists warnings. A top-level code and message give the outcome: TRANSLATIONS_SAVED (200, every row saved), TRANSLATIONS_PARTIALLY_SAVED (200, success: true; the message counts saved and failed rows and names the failure reasons, e.g. "2 saved, 1 failed. No source text found for the requested fields (description).") TRANSLATIONS_NOT_SAVED_RETRY (503 with a Retry-After header, success: false; no row saved because every row failed only with TRANSLATION_WRITE_BUSY, so the same call can be sent again after error.details.retry_after_seconds) or TRANSLATIONS_NOT_SAVED (422, success: false; no row saved and at least one row failed for another reason). Both carry the same totals and results in error.details. With an Idempotency-Key, repeating the same request re-applies nothing that already saved and retries the failed rows. A write waits at most 2 seconds for other translation writes of the same item or of a clashing name or slug (for example a translation CSV import writing the same language); writes of other items, types and languages never wait. A row or call that fails with TRANSLATION_WRITE_BUSY (HTTP 503) saved nothing: send it again after error.details.retry_after_seconds (the call's Retry-After header says the same). Every row or call either saved or reports an error; none is left in an unknown state.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Idempotency-Key string

Optional key for this translation write. Reuse it only with the same payload when repeating the request.

Body parameters

Name Type Description
translations required array<object>

Up to 100 rows shaped as {id, locale, fields}. The only allowed field key is content.

Example: [{"fields":{"content":"Commande {{ order.number }} passée !"},"id":"0b6f1e2d-8c4a-4f3b-9e7d-2a1c5b8d9e04","locale":"fr"},{"fields":{"content":"Commande {{ order.number }} passée !"},"id":"0b6f1e2d-8c4a-4f3b-9e7d-2a1c5b8d9e04","locale":"de"},{"fields":{"content":"Commande {{ order.number }} passée !"},"id":"0b6f1e2d-8c4a-4f3b-9e7d-2a1c5b8d9e04","locale":"pt-BR"}]

Errors

  • 401 UNAUTHORIZED

    Authorization header missing, malformed, or token invalid/expired.

  • 402 SUBSCRIPTION_REQUIRED

    The store does not have an active or trialing subscription.

  • 403 STORE_API_SCOPE_REQUIRED

    Token is valid but lacks the required scope for this call.

  • 429 RATE_LIMITED

    The token's request allowance is exhausted. Retry after the Retry-After header.

  • 400 STORE_API_INVALID_REQUEST_BODY

    The body is not valid JSON or a row has an unknown key or a wrongly typed value.

  • 400 TRANSLATION_NO_WRITES_PROVIDED

    translations is empty.

  • 400 TRANSLATION_TOO_MANY_ROWS

    More than 100 rows; nothing is written.

  • 503 TRANSLATIONS_NOT_SAVED_RETRY

    No row saved and every row failed only with TRANSLATION_WRITE_BUSY: send the same request again after error.details.retry_after_seconds (also the Retry-After header). error.details also has totals and one results entry per row with its error.

  • 422 TRANSLATIONS_NOT_SAVED

    No row saved and at least one row failed with an error that sending again will not fix; error.details has totals and one results entry per row with its error.

  • 400 STORE_API_BODY_PROPERTY_UNKNOWN

    The body has a property this request does not accept. The message and error.details.properties list the allowed and required properties (nested for each object or list of objects).

  • 400 STORE_API_BODY_PROPERTY_INVALID

    A body property has the wrong type (error.details.expected_type). The message and error.details.properties list the allowed and required properties.

Get a message template translation

GET read_marketing + read_translations

Fetch one message template's text in another store language.

A message template is one SMS or WhatsApp text: one message type and channel, addressed here by the id that List message templates and Get a message template return. Its content translates per store language; a customer whose language has a translation receives it, every other customer the template's own text. A translation keeps the original's values and tags exactly ({{ ... }} and {% ... %}, in any order within the same block): only the text around them changes, and one that does not is refused with MARKETING_TRANSLATION_VARIABLES_MISMATCH and details.variables listing what to keep. It must not be blank (MESSAGE_TEMPLATE_CONTENT_REQUIRED) and holds at most the template's max_content_length characters (MESSAGE_TEMPLATE_CONTENT_TOO_LONG). A translation written against an earlier original is reported outdated. Store Admin, the Tringify mobile app, translation CSV (resource message_template), AI translation and MCP translate the same texts. Each change sends message_templates/translations/update, or message_templates/translations/delete when a translation is cleared. Returns the stored content translation in the selected locale with is_outdated; a template without a translation in this locale returns an empty fields object. Fields without a translation in this locale are omitted from the response. An omitted field is not empty: shoppers see the store's base-language value, which the resource's own GET endpoint returns.

Path parameters

Name Type Description
id required integer

Message template ID.

Example: 7
locale required string

Enabled non-default store locale.

Example: fr

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 TRANSLATION_LOCALE_NOT_ENABLED

    Locale is not enabled for this store.

  • 400 TRANSLATION_DEFAULT_LOCALE_FORBIDDEN

    Translations cannot target the store's default locale, the language of the template's own text.

  • 400 TRANSLATION_INVALID_RESOURCE_ID

    The template ID is not a UUID.

  • 400 TRANSLATION_RESOURCE_ID_NOT_IN_STORE

    The template does not exist in this store.

Set a message template translation

PUT write_marketing + write_translations

Set or clear one message template's text in another store language.

A message template is one SMS or WhatsApp text: one message type and channel, addressed here by the id that List message templates and Get a message template return. Its content translates per store language; a customer whose language has a translation receives it, every other customer the template's own text. A translation keeps the original's values and tags exactly ({{ ... }} and {% ... %}, in any order within the same block): only the text around them changes, and one that does not is refused with MARKETING_TRANSLATION_VARIABLES_MISMATCH and details.variables listing what to keep. It must not be blank (MESSAGE_TEMPLATE_CONTENT_REQUIRED) and holds at most the template's max_content_length characters (MESSAGE_TEMPLATE_CONTENT_TOO_LONG). A translation written against an earlier original is reported outdated. Store Admin, the Tringify mobile app, translation CSV (resource message_template), AI translation and MCP translate the same texts. Each change sends message_templates/translations/update, or message_templates/translations/delete when a translation is cleared. Only content is translatable. Send an empty string to clear the translation; customers in that language then receive the template's own text. A write waits at most 2 seconds for other translation writes of the same item or of a clashing name or slug (for example a translation CSV import writing the same language); writes of other items, types and languages never wait. A row or call that fails with TRANSLATION_WRITE_BUSY (HTTP 503) saved nothing: send it again after error.details.retry_after_seconds (the call's Retry-After header says the same). Every row or call either saved or reports an error; none is left in an unknown state.

Path parameters

Name Type Description
id required integer

Message template ID.

Example: 7
locale required string

Enabled non-default store locale.

Example: fr

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Idempotency-Key string

Optional key for this translation write. Reuse it only with the same payload when repeating the request.

Body parameters

Name Type Description
translations required object

Field-keyed translation values. The only allowed field is content.

Example: {"content": "Commande {{ order.number }} passée !"}

Errors

  • 400 TRANSLATION_LOCALE_NOT_ENABLED

    Locale is not enabled for this store.

  • 400 TRANSLATION_DEFAULT_LOCALE_FORBIDDEN

    Translations cannot target the store's default locale, the language of the template's own text.

  • 400 TRANSLATION_INVALID_RESOURCE_ID

    The template ID is not a UUID.

  • 400 TRANSLATION_RESOURCE_ID_NOT_IN_STORE

    The template does not exist in this store.

  • 400 STORE_API_INVALID_REQUEST_BODY

    Request body must be a JSON object containing only documented fields; error.details.field identifies an unknown field.

  • 400 TRANSLATION_FIELDS_REQUIRED

    translations must contain content.

  • 400 TRANSLATION_FIELD_NOT_TRANSLATABLE

    A field other than content was sent.

  • 400 MESSAGE_TEMPLATE_CONTENT_REQUIRED

    The translation is blank (only spaces). Send an empty string to clear it.

  • 400 MESSAGE_TEMPLATE_CONTENT_TOO_LONG

    The translation is longer than the template content limit; details.max is the limit.

  • 400 MARKETING_TRANSLATION_VARIABLES_MISMATCH

    The translation does not keep the original's values and tags; details.variables lists them.

  • 400 TRANSLATION_NO_SOURCE_TEXT

    The template has no text to translate.

  • 503 TRANSLATION_WRITE_BUSY

    Other translation writes held the item or a clashing name or slug for more than 2 seconds; nothing was saved. Send the request again after error.details.retry_after_seconds (also the Retry-After header).

  • 400 STORE_API_BODY_PROPERTY_UNKNOWN

    The body has a property this request does not accept. The message and error.details.properties list the allowed and required properties (nested for each object or list of objects).

  • 400 STORE_API_BODY_PROPERTY_INVALID

    A body property has the wrong type (error.details.expected_type). The message and error.details.properties list the allowed and required properties.