Skip to content
Dashboard

Translations

Most text that guests and staff read in SuiteOp, such as manual titles, department names and upsell copy, isn’t stored on the record itself. The record holds a translation ID (a field such as titleId or nameId), and the text lives in that translation, once per language. This guide covers reading that text, repairing it after a rename and filling in a language. Every field is listed on the operation’s page in the API Reference.

OperationRequestPermission
getTranslationEntriesGET /translations/{translationId}/entriesAny permission, then per domain (see below)
getTranslationEntriesBatchGET /translations/entriesAny permission, then per domain (see below)
retranslateGuideTextPOST /translations/{translationId}/retranslatemodify_guides
initializeLanguageTranslationsPOST /translations/initialize-languagemanage_organization
getLanguageCoverageGET /translations/language-coveragemanage_organization
createTranslationPOST /translationsmodify_tasks

Paths are relative to your region’s base URL, for example https://api-us.suiteop.com/api/v1. See Authentication for permissions.

  • A translation is one piece of text, identified by a translation ID. Pass that ID, never the ID of the manual or task that holds it.
  • An entry is the text of that translation in one language: language, text and method. method records how the entry got there: manual (written or edited by a person), automatic (machine-translated), recursive, or null (older rows; treated as hand-written).
  • Machine translation runs in the background. Operations that translate return as soon as the work is queued. Languages appear in the entries as the jobs finish.
  • Hand-written text is protected when you rename a manual category. updatePortalManualCategory re-translates the other languages only when every one of them is machine output (an entry whose method is null counts as hand-written). If anyone wrote or reviewed a translation by hand, only English changes. retranslateGuideText is how you push the new wording to the other languages anyway. Other updates are not protected this way: changing an upsell’s title or description with updateUpsell re-translates every other language, overwriting hand-written translations.

The languages are en, es, fr, nl, de, zh, ar, it, bg, ja, pt, el, cs, he, uk, ru, id and ka. Machine translation targets the languages enabled for your organization, plus English.

Terminal window
curl "https://api-us.suiteop.com/api/v1/translations/3f1c9a2e-…/entries" \
-H "Authorization: Bearer sk_live_your_key_here"
{
"data": [
{ "language": "en", "text": "Kitchen appliances", "method": "manual" },
{ "language": "fr", "text": "Appareils de cuisine", "method": "automatic" }
],
"meta": { "requestId": "…" }
}

To read many at once, repeat translationIds (up to 50):

Terminal window
curl "https://api-us.suiteop.com/api/v1/translations/entries?translationIds=3f1c9a2e-…&translationIds=8b0d4f71-…" \
-H "Authorization: Bearer sk_live_your_key_here"

data is an object keyed by each ID you asked for, and each value is the same array of entries.

Who can read what:

  • The operations only need the credential to hold at least one permission. Each translation is then checked against the domain it belongs to: you need that domain’s view permission or its write permission. For example, manual and upsell copy needs view_guides or modify_guides, task copy needs view_tasks or modify_tasks, and property copy needs view_properties or modify_properties. Pre-arrival step, guest portal and upsell text is also readable with view_properties or modify_properties, because the operations that return those IDs need them.
  • Without the right permission, getTranslationEntries returns 403 with Missing permission: one of …, naming the permissions that would work. A translation that can’t be attributed to any domain returns 403 This translation is not readable through the public API.
  • An ID from another organization, or one tied to properties an OAuth token can’t reach, returns an empty array rather than an error.
  • The batch form never refuses an individual ID: an ID you can’t read comes back as an empty array, the same as a translation with no entries yet.

When you rename guide text in English and an operator had hand-written any other language, those languages keep the old wording. Re-translate them from the new English:

  1. Rename the text. For example, PATCH /portal-manual-categories/{id} with {"title": "Kitchen appliances"} (needs modify_guides). The response includes titleId.
  2. Re-translate that titleId:
Terminal window
curl -X POST https://api-us.suiteop.com/api/v1/translations/3f1c9a2e-…/retranslate \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{"sourceLanguage": "en", "overrideExisting": true}'
{
"data": { "translationId": "3f1c9a2e-…" },
"meta": { "requestId": "…" }
}
  1. The response is 200 and only echoes the ID. The translations run in the background, so read the result with GET /translations/{translationId}/entries.

Field notes:

  • Both fields are required. A request without sourceLanguage or overrideExisting is refused with 400.
  • overrideExisting: true overwrites every other language, hand-written and reviewed translations included. false only fills languages that have no entry yet.
  • sourceLanguage is a preference. Hand-written text wins: if your language holds machine output and another language holds hand-written text, that text is used as the source.
  • Only guide text is accepted: the text of guide items and lists, manuals, manual categories, events, upsells and fee products. Any other translation ID, including one from another organization, returns 404.

POST /translations/initialize-language machine-translates existing organization content into one language, filling only the gaps. Text that already exists in that language is skipped, so nothing hand-written is overwritten.

Terminal window
curl -X POST https://api-us.suiteop.com/api/v1/translations/initialize-language \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
-H "Content-Type: application/json" \
-d '{"language": "fr"}'

The response is 200 with counters for the work that was started, not finished: enqueued, deduplicated, hydrationSkipped and enqueueFailed. This call doesn’t enable the language for your organization; enable it in settings first, or nothing displays the new entries.

GET /translations/language-coverage shows where the gaps are: total translatable records, byLanguage with translated and missing counts per language (English first), and inFlight, the records still being translated. The counts aren’t taken at a single instant, so a gap that just closed can still show as open.

POST /translations creates a translation for pre-arrival question copy, the titleMlTextId of a question or the nameMlTextId of an option used by createPrecheckStep. It accepts only the sourceTable values precheck_question, precheck_option and precheck_step_detail. sourceTable, contentTag, inputType and text are required, and language defaults to en. The response is 201 with data.translationId. The text is stored in that one language and isn’t machine-translated.