# API Reference Source: https://developers.phrase.com/en/api/overview Explore Phrase's APIs for localization and translation management — including Strings, TMS, Language AI, Studio, Connectors, Quality Evaluator, and Content Groups. Phrase offers a suite of APIs to help you manage localization at scale - from translating dynamic content to integrating with your translation workflows. ## Choosing an API All Phrase APIs use REST over HTTPS and authenticate via OAuth 2.0 tokens issued by the Platform API. Choose the API that matches your use case: * **Strings** — key-based localization for software products; use when you need branching, version control, or multi-version release management. * **TMS** — translation workflow automation; use when you need project management, job tracking, translation memory, or delivery pipelines. * **Language AI** — MT/LLM aggregation and quality evaluation; use when you need to select the best machine translation output or score translation quality programmatically. * **Studio** — audio and video transcription, translation, and dubbing; use for media content in 100+ languages. * **Connectors** — custom integration flows; use when you need to connect Phrase to external systems beyond built-in integrations. * **Quality Evaluator** — AI-powered translation quality checks; use when you need reusable quality profiles and segment-level evaluation. * **Style Guides** — organization-wide writing guidelines; use when you need to keep translations and authored content on-brand with versioned, per-language style guides. * **Content Groups** — organize projects, style guides, and style rules into groups; use when you need to coordinate workflows across multiple Phrase products. Rate limits apply per API product. Check each product's introduction page for specific limits before building high-volume integrations. } href="/en/api/platform/introduction"> Platform APIs that provide unified authorization across Phrase products. } href="/en/api/strings/introduction"> APIs for key-based product localization with branching and version control for multi-version releases at scale. } href="/en/api/tms/latest/introduction"> APIs to automate translation workflows (TMS: Translation Management System), from projects and jobs to translation memory and delivery at scale. } href="/en/api/language-ai/introduction"> APIs for aggregating MT (Machine Translation) and LLM (Large Language Model) providers, selecting the best output, and evaluating translation quality. } href="/en/api/studio/introduction"> AI-powered audio and video processing for transcription, translation, and dubbing. Process content in over 100 languages with advanced features like glossaries and pronunciations. } href="/en/api/connectors/introduction"> A tool for building custom flows using Phrase Integrations. Easily connect localization processes with external systems and extend built-in integrations with your own functionality. } href="/en/api/quality-evaluator/latest/introduction"> APIs for automatically assessing translation quality using LLM-powered checks resolved from Style Guide Rules and Content Groups. } href="/en/api/style-guides/introduction"> Manage organization-wide writing guidelines that keep translations and authored content on-brand. Upload Markdown style guides per language and version every revision. } href="/en/api/control-hub/introduction"> APIs for organizing platform objects — projects, style guides, and style rules — into content groups for coordinated workflows across Phrase products. # Authentication Source: https://developers.phrase.com/en/api/platform/authentication Users can generate new API Tokens in the User Profile/Access Tokens tab in [Phrase Platform Settings page](https://eu.phrase.com/idm-ui/settings/access-tokens). Supported applications are: * Phrase Connectors API * Phrase Language AI * Phrase Strings * Phrase Studio * Phrase TMS * Quality Evaluator API * Phrase Style Guides * Phrase Content Groups #### Exchanging API tokens for JWT Exchange the generated API Token for Access Token using Phrase Platform OAuth Token endpoint with `urn:ietf:params:oauth:grant-type:token-exchange` grant type. This is extension of OAuth basic grants which is specified in OAuth 2.0 Token Exchange ([RFC-8693](https://www.rfc-editor.org/rfc/rfc8693.html)). Supported parameters are: | Parameter name | Value | Required | | ---------------------- | ------------------------------------------------- | -------- | | `grant_type` | `urn:ietf:params:oauth:grant-type:token-exchange` | yes | | `subject_token` | *API-TOKEN* | yes | | `subject_token_type` | `urn:phrase:params:oauth:token-type:api_token` | no | | `requested_token_type` | `urn:ietf:params:oauth:token-type:access_token` | no | Other fields from the Specification are not supported at the moment. Main endpoint URLs: * `https://eu.phrase.com/idm/oauth/token` (EU datacenter) * `https://us.phrase.com/idm/oauth/token` (US datacenter) ##### Sample request ```http theme={null} POST https://eu.phrase.com/idm/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token=API-TOKEN ``` With [curl](https://curl.se/): ```shell theme={null} # EU region curl -X POST https://eu.phrase.com/idm/oauth/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \ -d 'subject_token=API-TOKEN' # US region curl -X POST https://us.phrase.com/idm/oauth/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \ -d 'subject_token=API-TOKEN' ``` The response is in JSON format: ```json theme={null} { "access_token": "GENERATED-JWT", "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", "token_type": "Bearer", "expires_in": 14399 } ``` * `access_token` - the generated JWT access token * `issued_token_type` - the type of returned token, always `urn:ietf:params:oauth:token-type:access_token` * `token_type` - how to use the token, always `Bearer` * `expires_in` - validity of the token in seconds #### Machine-to-Machine authentication (Service Accounts) For server-to-server integrations that don't involve a human user, create a Service Account in **Organization Settings → Service Accounts**. Each Service Account provisions a bot user scoped to one or more Phrase products, and authenticates using the standard OAuth 2.0 Client Credentials flow — no API token or token-exchange step needed. Creating a Service Account generates a `client_id` and `client_secret`, shown once. Exchange them directly for an access token against the same Phrase Platform OAuth Token endpoint. Supported parameters are: | Parameter name | Value | Required | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | `grant_type` | `client_credentials` | yes | | `client_id` | *CLIENT-ID* | yes | | `client_secret` | *CLIENT-SECRET* | yes | | `resource` | Space-separated list of product UIDs (e.g. `strings`, `tms`) to restrict the token to. Omit to cover every product configured on the Service Account. | no | | `scope` | Space-separated list of requested scopes. Must be granted by at least one of the targeted products — a product that doesn't grant any requested scope is simply left out of the resulting token rather than failing the whole request. Omit to get each targeted product's full configured scope. | no | ##### Sample request ```http theme={null} POST https://eu.phrase.com/idm/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=client_credentials&client_id=CLIENT-ID&client_secret=CLIENT-SECRET ``` With [curl](https://curl.se/): ```shell theme={null} # EU region curl -X POST https://eu.phrase.com/idm/oauth/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=client_credentials' \ -d 'client_id=CLIENT-ID' \ -d 'client_secret=CLIENT-SECRET' # US region curl -X POST https://us.phrase.com/idm/oauth/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=client_credentials' \ -d 'client_id=CLIENT-ID' \ -d 'client_secret=CLIENT-SECRET' ``` The response is in JSON format: ```json theme={null} { "access_token": "GENERATED-JWT", "token_type": "Bearer", "expires_in": 14399, "scope": "strings:read strings:write tms:default" } ``` * `access_token` - the generated JWT access token * `token_type` - how to use the token, always `Bearer` * `expires_in` - validity of the token in seconds * `scope` - space-separated, prefixed by product UID (e.g. `strings:read`); a product with no requested/configured scope still appears in the token's audience without contributing to this claim ##### Good to know * Bot users show up in product UIs with a bot badge but can't log in interactively. They can read/write content, run analyses, and work with translation memories — but can't create or modify human users, or be assigned as project owners. They don't count toward seat quotas. The only way to remove a bot user is to delete its Service Account. #### Using JWT in APIs Use the token to access Platform APIs of specific application - passing it in HTTP Authorization Header: ``` Authorization: Bearer GENERATED-JWT ``` # Introduction Source: https://developers.phrase.com/en/api/platform/introduction ## Phrase Platform API Reference 1.0.0 Phrase Platform related APIs serving unified authorization experience to all [Phrase Platform](https://phrase.com/) products. # Token Endpoint Source: https://developers.phrase.com/en/api/platform/oauth/token-endpoint /openapi/phrase-platform.json post /oauth/token Token Endpoint provides tokens according to **OAuth 2.0/OIDC 1.0** (RFC-6749) specifications and its extension **OAuth 2.0 Token Exchange** (RFC-8693). # Create user Source: https://developers.phrase.com/en/api/platform/scim/create-user /openapi/phrase-platform.json post /scim/Users Provisions a new user into the authenticated organization using the SCIM `urn:ietf:params:scim:schemas:core:2.0:User` schema. If a user with the same `userName` or primary email already exists in another organization within the same customer group (SSO-linked), the user is added to this organization instead of being created. # Delete user Source: https://developers.phrase.com/en/api/platform/scim/delete-user /openapi/phrase-platform.json delete /scim/Users/{userUid} Deprovisions a user from the authenticated organization. The exact effect depends on the user's membership type: - **Internal user, single-org**: removes all organization memberships and deletes the identity. - **Internal user, multi-org (same SSO customer group)**: removes only the membership in this organization; the identity and other memberships are preserved. - **External user**: removes only the membership in this organization. Bot identities and the last owner of an organization cannot be deleted. Returns `204 No Content` on success. # Get user Source: https://developers.phrase.com/en/api/platform/scim/get-user /openapi/phrase-platform.json get /scim/Users/{userUid} Returns a single user by their Phrase Platform identity UID. # List resource types Source: https://developers.phrase.com/en/api/platform/scim/list-resource-types /openapi/phrase-platform.json get /scim/ResourceTypes Returns the resource types supported by this SCIM service provider (RFC 7644 Section 4). No authentication is required. # List schemas Source: https://developers.phrase.com/en/api/platform/scim/list-schemas /openapi/phrase-platform.json get /scim/Schemas Returns all SCIM schemas supported by this service provider (RFC 7643 Section 7, RFC 7644 Section 4). No authentication is required. # List users Source: https://developers.phrase.com/en/api/platform/scim/list-users /openapi/phrase-platform.json get /scim/Users Returns a paginated list of users belonging to the authenticated organization. Supports [SCIM filtering](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.2.2) using the `eq` comparator on the following attributes: - `id` - `externalId` - `userName` - `name.givenName` - `name.familyName` - `emails.value` Only a single filter condition is supported — compound expressions (e.g. AND) return `400`. Filter attribute names are case-insensitive. # Retrieve service provider configuration Source: https://developers.phrase.com/en/api/platform/scim/retrieve-service-provider-configuration /openapi/phrase-platform.json get /scim/ServiceProviderConfig Returns the SCIM service provider's configuration, including supported features such as filtering, patch operations, and authentication schemes (RFC 7643 Section 5, RFC 7644 Section 4). No authentication is required. # Update user Source: https://developers.phrase.com/en/api/platform/scim/update-user /openapi/phrase-platform.json put /scim/Users/{userUid} Updates a user's attributes. Only fields explicitly provided with a non-null, non-blank value are written — omitted, null, blank, or empty-list fields keep their current values. Updatable fields: `userName`, `name.givenName`, `name.familyName`, `emails` (primary address), `externalId`, `locale`, `timezone`, `active`. The `active` field is always applied from the request body regardless of its previous value. Bot identities and users managed externally (EXTERNAL membership) cannot be updated. Role assignments in the request body are ignored — role updates via SCIM are not supported. # Update user Source: https://developers.phrase.com/en/api/platform/scim/update-user-1 /openapi/phrase-platform.json patch /scim/Users/{userUid} Partially updates a user's attributes using SCIM PATCH operations (RFC 7644 Section 3.5.2). Only the `replace` operation is supported. Supported target paths: - `active` - `externalId` - `userName` - `name.givenName` - `name.familyName` - `name` (complex object) - `emails` (complex array) - `emails[type eq "work"].value` When `path` is omitted, the value must be an object whose fields are merged into the user resource. Returns `204 No Content` on success. # Get a single account Source: https://developers.phrase.com/en/api/strings/accounts/get-a-single-account /openapi/phrase-strings.json get /accounts/{id} Get details on a single account. # List accounts Source: https://developers.phrase.com/en/api/strings/accounts/list-accounts /openapi/phrase-strings.json get /accounts List all accounts the current user has access to. # Authentication Source: https://developers.phrase.com/en/api/strings/authentication There are two different ways to authenticate when performing API requests: * Phrase Platform API tokens * E-Mail and password * Oauth Access Token ## Phrase Platform API tokens Preferred method – use this for a single, consistent way to access all Phrase Platform APIs. Generate a Phrase Platform JWT token as described [here](/en/api/platform/authentication) ## E-Mail and password To get started easily, you can use HTTP Basic authentication with your email and password: ``` $ curl -u username:password "https://api.phrase.com/v2/projects" ``` ## OAuth via Access Tokens You can create and manage access tokens in your [profile settings](https://app.phrase.com/settings/oauth_access_tokens) in Translation Center or via the [Authorizations API](https://developers.phrase.com/api/#tag--Authorizations). Simply pass the access token as the username of your request: ``` $ curl -u ACCESS_TOKEN: "https://api.phrase.com/v2/projects" ``` or send the access token via the `Authorization` header field: ``` $ curl -H "Authorization: token ACCESS_TOKEN" https://api.phrase.com/v2/projects ``` ### Send via parameter As JSONP (and other) requests cannot send HTTP Basic Auth credentials, a special query parameter `access_token` can be used: ``` curl "https://api.phrase.com/v2/projects?access_token=ACCESS_TOKEN" ``` You should only use this transport method if sending the authentication via header or Basic authentication is not possible. ## Two-Factor-Authentication Users with Two-Factor-Authentication enabled have to send a valid token along their request with certain authentication methods (such as Basic authentication). The necessity of a Two-Factor-Authentication token is indicated by the `X-PhraseApp-OTP: required; :MFA-type` header in the response. The `:MFA-type` field indicates the source of the token, e.g. `app` (refers to your Authenticator application): ``` X-PhraseApp-OTP: required; app ``` To provide a Two-Factor-Authentication token you can simply send it in the header of the request: ``` curl -H "X-PhraseApp-OTP: MFA-TOKEN" -u EMAIL https://api.phrase.com/v2/projects ``` Since Two-Factor-Authentication tokens usually expire quickly, we recommend using an alternative authentication method such as OAuth access tokens. ## Multiple Accounts Some endpoints require the account ID to be specified if the authenticated user is a member of multiple accounts. You can find the eight-digit account ID inside [Translation Center](https://app.phrase.com/) by switching to the desired account and then visiting the account details page. If required, you can specify the account just like a normal parameter within the request. # Create an authorization Source: https://developers.phrase.com/en/api/strings/authorizations/create-an-authorization /openapi/phrase-strings.json post /authorizations Create a new authorization. # Delete an authorization Source: https://developers.phrase.com/en/api/strings/authorizations/delete-an-authorization /openapi/phrase-strings.json delete /authorizations/{id} Delete an existing authorization. API calls using that token will stop working. # Get a single authorization Source: https://developers.phrase.com/en/api/strings/authorizations/get-a-single-authorization /openapi/phrase-strings.json get /authorizations/{id} Get details on a single authorization. # List authorizations Source: https://developers.phrase.com/en/api/strings/authorizations/list-authorizations /openapi/phrase-strings.json get /authorizations List all your authorizations. # Update an authorization Source: https://developers.phrase.com/en/api/strings/authorizations/update-an-authorization /openapi/phrase-strings.json patch /authorizations/{id} Update an existing authorization. # List automation events for an account Source: https://developers.phrase.com/en/api/strings/automation-events/list-automation-events-for-an-account /openapi/phrase-strings.json get /accounts/{account_id}/automation_events Returns the run history across all automations in the account, newest-first. Use `automation_id` to narrow results to a single automation. Use `project_id` or `project_ids` to narrow by project. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # List events for an automation Source: https://developers.phrase.com/en/api/strings/automation-events/list-events-for-an-automation /openapi/phrase-strings.json get /accounts/{account_id}/automations/{automation_id}/events Returns the run history for a specific automation, newest-first. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # Activate an automation Source: https://developers.phrase.com/en/api/strings/automations/activate-an-automation /openapi/phrase-strings.json post /accounts/{account_id}/automations/{automation_id}/activate Activate an automation. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # Create an automation Source: https://developers.phrase.com/en/api/strings/automations/create-an-automation /openapi/phrase-strings.json post /accounts/{account_id}/automations Create a new automation. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # Deactivate an automation Source: https://developers.phrase.com/en/api/strings/automations/deactivate-an-automation /openapi/phrase-strings.json post /accounts/{account_id}/automations/{automation_id}/deactivate Deactivate an automation. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # Destroy automation Source: https://developers.phrase.com/en/api/strings/automations/destroy-automation /openapi/phrase-strings.json delete /accounts/{account_id}/automations/{automation_id} Destroy an automation of an account. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # Get a single automation Source: https://developers.phrase.com/en/api/strings/automations/get-a-single-automation /openapi/phrase-strings.json get /accounts/{account_id}/automations/{automation_id} Get details of a single automation. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # List automations Source: https://developers.phrase.com/en/api/strings/automations/list-automations /openapi/phrase-strings.json get /accounts/{account_id}/automations List all automations for an account. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # Trigger an automation Source: https://developers.phrase.com/en/api/strings/automations/trigger-an-automation /openapi/phrase-strings.json post /accounts/{account_id}/automations/{automation_id}/trigger Trigger an automation. # Update an automation Source: https://developers.phrase.com/en/api/strings/automations/update-an-automation /openapi/phrase-strings.json patch /accounts/{account_id}/automations/{automation_id} Update an existing automation. For feature availability, see [Jobs (Strings)](https://support.phrase.com/hc/en-us/articles/5784100517788-Jobs-Strings). # Create a blocked key Source: https://developers.phrase.com/en/api/strings/blacklisted-keys/create-a-blocked-key /openapi/phrase-strings.json post /projects/{project_id}/blacklisted_keys Create a new rule for blocking keys. # Delete a blocked key Source: https://developers.phrase.com/en/api/strings/blacklisted-keys/delete-a-blocked-key /openapi/phrase-strings.json delete /projects/{project_id}/blacklisted_keys/{id} Delete an existing rule for blocking keys. # Get a single blocked key Source: https://developers.phrase.com/en/api/strings/blacklisted-keys/get-a-single-blocked-key /openapi/phrase-strings.json get /projects/{project_id}/blacklisted_keys/{id} Get details on a single rule for blocking keys for a given project. # List blocked keys Source: https://developers.phrase.com/en/api/strings/blacklisted-keys/list-blocked-keys /openapi/phrase-strings.json get /projects/{project_id}/blacklisted_keys List all rules for blocking keys for the given project. # Update a blocked key Source: https://developers.phrase.com/en/api/strings/blacklisted-keys/update-a-blocked-key /openapi/phrase-strings.json patch /projects/{project_id}/blacklisted_keys/{id} Update an existing rule for blocking keys. # Compare branches Source: https://developers.phrase.com/en/api/strings/branches/compare-branches /openapi/phrase-strings.json get /projects/{project_id}/branches/{name}/compare Compare branch with main branch. *Note: Comparing a branch may take several minutes depending on the project size. Consider using the `POST /compare` endpoint for creating comparison asynchronously.* # Create a branch Source: https://developers.phrase.com/en/api/strings/branches/create-a-branch /openapi/phrase-strings.json post /projects/{project_id}/branches Create a new branch. Branch project provisioning runs asynchronously, so the newly created branch is returned in a transitional state (typically `creating_branch`) and only reaches `success` once the underlying project has been set up. Poll the branch resource until its `state` becomes `success` before performing further operations on it. Requires the Branching feature to be enabled on the account. *Note: Creating a new branch may take several minutes depending on the project size.* # Create comparison (async.) Source: https://developers.phrase.com/en/api/strings/branches/create-comparison-async /openapi/phrase-strings.json post /projects/{project_id}/branches/{name}/compare Create a branch comparison asynchronously. # Delete a branch Source: https://developers.phrase.com/en/api/strings/branches/delete-a-branch /openapi/phrase-strings.json delete /projects/{project_id}/branches/{name} Delete an existing branch. A branch cannot be deleted while it still has open jobs or open translation orders attached to its branch project — in that case the request is rejected with `409 Conflict`. A branch whose current `state` does not allow deletion (for example, while a merge or sync is in progress) is rejected with `422 Unprocessable Entity`. Requires the Branching feature to be enabled on the account. # Get a single branch Source: https://developers.phrase.com/en/api/strings/branches/get-a-single-branch /openapi/phrase-strings.json get /projects/{project_id}/branches/{name} Get details on a single branch for a given project. Requires the Branching feature to be enabled on the account. # List branches Source: https://developers.phrase.com/en/api/strings/branches/list-branches /openapi/phrase-strings.json get /projects/{project_id}/branches List all branches of the current project. Requires the Branching feature to be enabled on the account. # Merge a branch Source: https://developers.phrase.com/en/api/strings/branches/merge-a-branch /openapi/phrase-strings.json patch /projects/{project_id}/branches/{name}/merge Merge an existing branch back into its base branch. The merge runs asynchronously. The branch transitions to `merging_branch` and settles in `merged`, `merge_error`, or `merge_conflict` once the background job completes; the response body for this request is empty. Poll the branch resource to observe the final state. A branch cannot be merged while it still has open jobs or open translation orders attached to its branch project — in that case the request is rejected with `409 Conflict`. A branch whose current `state` does not allow a merge is rejected with `422 Unprocessable Entity`. Requires the Branching feature to be enabled on the account. *Note: Merging a branch may take several minutes depending on diff size.* # Sync a branch Source: https://developers.phrase.com/en/api/strings/branches/sync-a-branch /openapi/phrase-strings.json patch /projects/{project_id}/branches/{name}/sync Pull changes from the base branch into this branch, applying the chosen conflict-resolution strategy. The sync runs asynchronously. The branch transitions to `syncing_branch` and settles back into `success` (or `merge_conflict` / `branch_error`) once the background job completes; the response body for this request is empty. Poll the branch resource to observe the final state. Only branches created with the newer branching system can be synced. Requests against branches from the older system, or against branches whose current state does not allow a sync, are rejected with `422 Unprocessable Entity` and an empty body. Requires the Branching feature to be enabled on the account. # Update a branch Source: https://developers.phrase.com/en/api/strings/branches/update-a-branch /openapi/phrase-strings.json patch /projects/{project_id}/branches/{name} Update an existing branch. Only the branch name can be changed. Requires the Branching feature to be enabled on the account. # Create a reaction Source: https://developers.phrase.com/en/api/strings/comment-reactions/create-a-reaction /openapi/phrase-strings.json post /projects/{project_id}/keys/{key_id}/comments/{comment_id}/reactions Create a new reaction for a comment. # Delete a reaction Source: https://developers.phrase.com/en/api/strings/comment-reactions/delete-a-reaction /openapi/phrase-strings.json delete /projects/{project_id}/keys/{key_id}/comments/{comment_id}/reactions/{id} Delete an existing reaction. # Get a single reaction Source: https://developers.phrase.com/en/api/strings/comment-reactions/get-a-single-reaction /openapi/phrase-strings.json get /projects/{project_id}/keys/{key_id}/comments/{comment_id}/reactions/{id} Get details on a single reaction. # List reactions Source: https://developers.phrase.com/en/api/strings/comment-reactions/list-reactions /openapi/phrase-strings.json get /projects/{project_id}/keys/{key_id}/comments/{comment_id}/reactions List all reactions for a comment. # Create a reply Source: https://developers.phrase.com/en/api/strings/comment-replies/create-a-reply /openapi/phrase-strings.json post /projects/{project_id}/keys/{key_id}/comments/{comment_id}/replies Create a new reply for a comment. # Delete a reply Source: https://developers.phrase.com/en/api/strings/comment-replies/delete-a-reply /openapi/phrase-strings.json delete /projects/{project_id}/keys/{key_id}/comments/{comment_id}/replies/{id} Delete an existing reply. # Get a single reply Source: https://developers.phrase.com/en/api/strings/comment-replies/get-a-single-reply /openapi/phrase-strings.json get /projects/{project_id}/keys/{key_id}/comments/{comment_id}/replies/{id} Get details on a single reply. # List replies Source: https://developers.phrase.com/en/api/strings/comment-replies/list-replies /openapi/phrase-strings.json get /projects/{project_id}/keys/{key_id}/comments/{comment_id}/replies List all replies for a comment. # Mark a reply as read Source: https://developers.phrase.com/en/api/strings/comment-replies/mark-a-reply-as-read /openapi/phrase-strings.json patch /projects/{project_id}/keys/{key_id}/comments/{comment_id}/replies/{id}/mark_as_read Mark a reply as read. # Mark a reply as unread Source: https://developers.phrase.com/en/api/strings/comment-replies/mark-a-reply-as-unread /openapi/phrase-strings.json patch /projects/{project_id}/keys/{key_id}/comments/{comment_id}/replies/{id}/mark_as_unread Mark a reply as unread. # Check if comment is read Source: https://developers.phrase.com/en/api/strings/comments/check-if-comment-is-read /openapi/phrase-strings.json get /projects/{project_id}/keys/{key_id}/comments/{id}/read Check if comment was marked as read. Returns 204 if read, 404 if unread. # Create a comment Source: https://developers.phrase.com/en/api/strings/comments/create-a-comment /openapi/phrase-strings.json post /projects/{project_id}/keys/{key_id}/comments Create a new comment for a key. # Delete a comment Source: https://developers.phrase.com/en/api/strings/comments/delete-a-comment /openapi/phrase-strings.json delete /projects/{project_id}/keys/{key_id}/comments/{id} Delete an existing comment. # Get a single comment Source: https://developers.phrase.com/en/api/strings/comments/get-a-single-comment /openapi/phrase-strings.json get /projects/{project_id}/keys/{key_id}/comments/{id} Get details on a single comment. # List comments Source: https://developers.phrase.com/en/api/strings/comments/list-comments /openapi/phrase-strings.json get /projects/{project_id}/keys/{key_id}/comments List all comments for a key. # Mark a comment as read Source: https://developers.phrase.com/en/api/strings/comments/mark-a-comment-as-read /openapi/phrase-strings.json patch /projects/{project_id}/keys/{key_id}/comments/{id}/read Mark a comment as read. # Mark a comment as unread Source: https://developers.phrase.com/en/api/strings/comments/mark-a-comment-as-unread /openapi/phrase-strings.json delete /projects/{project_id}/keys/{key_id}/comments/{id}/read Mark a comment as unread. # Update a comment Source: https://developers.phrase.com/en/api/strings/comments/update-a-comment /openapi/phrase-strings.json patch /projects/{project_id}/keys/{key_id}/comments/{id} Update an existing comment. # Create a property Source: https://developers.phrase.com/en/api/strings/custom-metadata/create-a-property /openapi/phrase-strings.json post /accounts/{account_id}/custom_metadata/properties Create a new custom metadata property. # Destroy property Source: https://developers.phrase.com/en/api/strings/custom-metadata/destroy-property /openapi/phrase-strings.json delete /accounts/{account_id}/custom_metadata/properties/{id} Destroy a custom metadata property of an account. This endpoint is only available to accounts with advanced plans or above. # Get a single property Source: https://developers.phrase.com/en/api/strings/custom-metadata/get-a-single-property /openapi/phrase-strings.json get /accounts/{account_id}/custom_metadata/properties/{id} Get details of a single custom property. # List properties Source: https://developers.phrase.com/en/api/strings/custom-metadata/list-properties /openapi/phrase-strings.json get /accounts/{account_id}/custom_metadata/properties List all custom metadata properties for an account. This endpoint is only available to accounts with advanced plans or above. # Update a property Source: https://developers.phrase.com/en/api/strings/custom-metadata/update-a-property /openapi/phrase-strings.json patch /accounts/{account_id}/custom_metadata/properties/{id} Update an existing custom metadata property. # Create a distribution Source: https://developers.phrase.com/en/api/strings/distributions/create-a-distribution /openapi/phrase-strings.json post /accounts/{account_id}/distributions Create a new distribution. # Delete a distribution Source: https://developers.phrase.com/en/api/strings/distributions/delete-a-distribution /openapi/phrase-strings.json delete /accounts/{account_id}/distributions/{id} Delete an existing distribution. # Get a single distribution Source: https://developers.phrase.com/en/api/strings/distributions/get-a-single-distribution /openapi/phrase-strings.json get /accounts/{account_id}/distributions/{id} Get details on a single distribution. # List distributions Source: https://developers.phrase.com/en/api/strings/distributions/list-distributions /openapi/phrase-strings.json get /accounts/{account_id}/distributions List all distributions for the given account. # Update a distribution Source: https://developers.phrase.com/en/api/strings/distributions/update-a-distribution /openapi/phrase-strings.json patch /accounts/{account_id}/distributions/{id} Update an existing distribution. # Delete document Source: https://developers.phrase.com/en/api/strings/documents/delete-document /openapi/phrase-strings.json delete /projects/{project_id}/documents/{id} Permanently deletes a document and all of its associated translation segments from the project. Use this when you want to remove a document that is no longer needed; the deletion cannot be reversed and all associated segments will be lost. # List documents Source: https://developers.phrase.com/en/api/strings/documents/list-documents /openapi/phrase-strings.json get /projects/{project_id}/documents Returns all documents in a project that the authenticated user has read access to. A Document is a source file — an HTML or DOCX file — that has been uploaded to Phrase Strings and whose content is segmented into translation keys for localization. Use this endpoint to enumerate documents before downloading, previewing, or triggering translation workflows for individual files. The q parameter performs a prefix match on the document name (case-insensitive). For example, passing q=invoice returns documents whose names begin with "invoice" but not documents containing "invoice" elsewhere in the name. # Create a Figma attachment Source: https://developers.phrase.com/en/api/strings/figma-attachments/create-a-figma-attachment /openapi/phrase-strings.json post /projects/{project_id}/figma_attachments Create a new Figma attachment. # Delete a Figma attachment Source: https://developers.phrase.com/en/api/strings/figma-attachments/delete-a-figma-attachment /openapi/phrase-strings.json delete /projects/{project_id}/figma_attachments/{id} Delete an existing Figma attachment. # Get a single Figma attachment Source: https://developers.phrase.com/en/api/strings/figma-attachments/get-a-single-figma-attachment /openapi/phrase-strings.json get /projects/{project_id}/figma_attachments/{id} Get details on a single Figma attachment for a given project. # List Figma attachments Source: https://developers.phrase.com/en/api/strings/figma-attachments/list-figma-attachments /openapi/phrase-strings.json get /projects/{project_id}/figma_attachments List all Figma attachments for the given project # Update a Figma attachment Source: https://developers.phrase.com/en/api/strings/figma-attachments/update-a-figma-attachment /openapi/phrase-strings.json patch /projects/{project_id}/figma_attachments/{id} Update an existing Figma attachment. # List formats Source: https://developers.phrase.com/en/api/strings/formats/list-formats /openapi/phrase-strings.json get /formats Returns all file formats that Phrase Strings supports. Use the api_name value from each format as the file_format parameter when uploading or downloading locale files. Not every format supports both directions: check the importable and exportable fields before using a format in a workflow. This endpoint does not require authentication and is not subject to rate limiting. # Getting started Source: https://developers.phrase.com/en/api/strings/getting-started ## API Endpoints ### EU data center ``` https://api.phrase.com/v2/ ``` ### US data center ``` https://api.us.app.phrase.com/v2/ ``` The API is only accessible via HTTPS and the current version is v2, which results in a base URL like: [https://api.phrase.com/v2/](https://api.phrase.com/v2/) depending on the datacenter. ## Usage [curl](http://curl.haxx.se/) is used primarily to send requests to Phrase Strings in the examples. On most you'll find a second variant using the [Phrase Strings API v2 client](https://phrase.com/cli/) that might be more convenient to handle. For further information check its [documentation](https://support.phrase.com/hc/en-us/articles/5808300599068). ## Use of HTTP Verbs Phrase Strings API v2 tries to use the appropriate HTTP verb for accessing each endpoint according to REST specification where possible: | Verb | Description | | ------ | ---------------------------------- | | GET | Retrieve one or multiple resources | | POST | Create a resource | | PUT | Update a resource | | PATCH | Update a resource (partially) | | DELETE | Delete a resource | ## Identification via User-Agent You must include the User-Agent header with the name of your application or project. It might be a good idea to include some sort of contact information as well, so that we can get in touch if necessary (e.g. to warn you about Rate-Limiting or badly formed requests). Examples of excellent User-Agent headers: ``` User-Agent: Example Mobile App (example@phrase.com) User-Agent: ACME Inc Python Client (http://example.com/contact) ``` If you don't send this header, you will receive a response with 400 Bad Request. ## Lists When you request a list of resources, the API will typically only return an array of resources including their most important attributes. For a detailed representation of the resource you should request its detailed representation. Lists are usually [paginated](/en/api/strings/pagination). ## Parameters Many endpoints support additional parameters, e.g. for pagination. When passing them in a GET request you can send them as HTTP query string parameters: ``` $ curl -u EMAIL_OR_ACCESS_TOKEN "https://api.phrase.com/v2/projects?page=2" ``` When performing a POST, PUT, PATCH or DELETE request, we recommend sending parameters that are not already included in the URL, as JSON body: ``` $ curl -H 'Content-Type: application/json' -d '{"name":"My new project"}' -u EMAIL_OR_ACCESS_TOKEN https://api.phrase.com/v2/projects ``` Encoding parameters as JSON means better support for types (boolean, integer) and usually better readability. Don't forget to set the correct Content-Type for your request. *The Content-Type header is omitted in some of the following examples for better readbility.* ## Errors ### Request Errors If a request contains invalid JSON or is missing a required parameter (besides resource attributes), the status `400 Bad Request` is returned: ``` { "message": "JSON could not be parsed" } ``` ### Validation Errors When the validation for a resource fails, the status `422 Unprocessable Entity` is returned, along with information on the affected fields: ``` { "message": "Validation Failed", "errors": [ { "resource": "Project", "field": "name", "message": "can't be blank" } ] } ``` ## Date Format Times and dates are returned and expected in [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) date format: ``` YYYY-MM-DDTHH:MM:SSZ ``` Instead of 'Z' for UTC time zone you can specify your time zone's locale offset using the following notation: ``` YYYY-MM-DDTHH:MM:SS¬±hh:mm ``` Example for CET (1 hour behind UTC): ``` 2015-03-31T13:00+01:00 ``` Please note that in HTTP headers, we will use the appropriate recommended date formats instead of ISO 8601. ## JSONP The Phrase Strings API supports [JSONP](http://en.wikipedia.org/wiki/JSONP) for all GET requests in order to deal with cross-domain request issues. Just send a `?callback` parameter along with the request to specify the Javascript function name to be called with the response content: ``` $ curl "https://api.phrase.com/v2/projects?callback=myFunction" ``` The response will include the normal output for that endpoint, along with a `meta` section including header data: ``` myFunction({ { "meta": { "status": 200, ... }, "data": [ { "id": "1234abcd1234abc1234abcd1234abc" ... } ] } }); ``` To authenticate a JSONP request, you can send a valid [access token](/en/api/strings/authentication#oauth-via-access-tokens) as the `?access_token` parameter along the request: ``` $ curl "https://api.phrase.com/v2/projects?callback=myFunction&access_token=ACCESS-TOKEN" ``` # Create a term base Source: https://developers.phrase.com/en/api/strings/glossaries/create-a-term-base /openapi/phrase-strings.json post /accounts/{account_id}/glossaries Create a new term base (previously: glossary). # Delete a term base Source: https://developers.phrase.com/en/api/strings/glossaries/delete-a-term-base /openapi/phrase-strings.json delete /accounts/{account_id}/glossaries/{id} Delete an existing term base (previously: glossary). # Get a single term base Source: https://developers.phrase.com/en/api/strings/glossaries/get-a-single-term-base /openapi/phrase-strings.json get /accounts/{account_id}/glossaries/{id} Get details on a single term base (previously: glossary). # List term bases Source: https://developers.phrase.com/en/api/strings/glossaries/list-term-bases /openapi/phrase-strings.json get /accounts/{account_id}/glossaries List all term bases (previously: glossaries) the current user has access to. # Update a term base Source: https://developers.phrase.com/en/api/strings/glossaries/update-a-term-base /openapi/phrase-strings.json patch /accounts/{account_id}/glossaries/{id} Update an existing term base (previously: glossary). # Create a translation for a term Source: https://developers.phrase.com/en/api/strings/glossary-term-translations/create-a-translation-for-a-term /openapi/phrase-strings.json post /accounts/{account_id}/glossaries/{glossary_id}/terms/{term_id}/translations Create a new translation for a term in a term base (previously: glossary). # Delete a translation for a term Source: https://developers.phrase.com/en/api/strings/glossary-term-translations/delete-a-translation-for-a-term /openapi/phrase-strings.json delete /accounts/{account_id}/glossaries/{glossary_id}/terms/{term_id}/translations/{id} Delete an existing translation of a term in a term base (previously: glossary). # Update a translation for a term Source: https://developers.phrase.com/en/api/strings/glossary-term-translations/update-a-translation-for-a-term /openapi/phrase-strings.json patch /accounts/{account_id}/glossaries/{glossary_id}/terms/{term_id}/translations/{id} Update an existing translation for a term in a term base (previously: glossary). # Create a term Source: https://developers.phrase.com/en/api/strings/glossary-terms/create-a-term /openapi/phrase-strings.json post /accounts/{account_id}/glossaries/{glossary_id}/terms Create a new term in a term base (previously: glossary). # Delete a term Source: https://developers.phrase.com/en/api/strings/glossary-terms/delete-a-term /openapi/phrase-strings.json delete /accounts/{account_id}/glossaries/{glossary_id}/terms/{id} Delete an existing term in a term base (previously: glossary). # Get a single term Source: https://developers.phrase.com/en/api/strings/glossary-terms/get-a-single-term /openapi/phrase-strings.json get /accounts/{account_id}/glossaries/{glossary_id}/terms/{id} Get details for a single term in the term base (previously: glossary). # List terms Source: https://developers.phrase.com/en/api/strings/glossary-terms/list-terms /openapi/phrase-strings.json get /accounts/{account_id}/glossaries/{glossary_id}/terms List all terms in term bases (previously: glossary) that the current user has access to. # Update a term Source: https://developers.phrase.com/en/api/strings/glossary-terms/update-a-term /openapi/phrase-strings.json patch /accounts/{account_id}/glossaries/{glossary_id}/terms/{id} Update an existing term in a term base (previously: glossary). # Build ICU skeletons Source: https://developers.phrase.com/en/api/strings/icu/build-icu-skeletons /openapi/phrase-strings.json post /icu/skeleton Generates ICU (International Components for Unicode) message format skeletons for a given source string across one or more locales. An ICU skeleton strips the literal text from a pluralized or select message while preserving its structural rules — argument names, plural categories, select cases, and ordinal forms — adjusted to the pluralization rules of each requested locale. Use this endpoint to normalize translation templates before importing them into locale files, or to validate that a source string carries the plural forms required by a target language. Either `content` or `id` must be provided — supplying both or neither returns 400. When `id` is used and the referenced translation does not exist, the endpoint returns 404. When the source string is not valid ICU message format syntax, the endpoint returns 422 with an `error` field describing the parse failure. # Introduction Source: https://developers.phrase.com/en/api/strings/introduction ## Phrase Strings API Reference 2.0.0 Phrase Strings is a translation management platform for software projects. You can collaborate on language file translation with your team or order translations through our platform. The API allows you to import locale files, download locale files, tag keys or interact in other ways with the localization data stored in Phrase Strings for your account. ## Developer tools Looking for an easier way to integrate? We provide a CLI and official API client libraries to help you get started quickly. Push and pull translation files directly from your terminal. Official clients for Ruby, Python, PHP, TypeScript, Java, and Go. # Pagination Source: https://developers.phrase.com/en/api/strings/pagination Endpoints that return a list or resources will usually return paginated results and include 25 items by default. To access further pages, use the `page` parameter: ``` $ curl -u EMAIL_OR_ACCESS_TOKEN "https://api.phrase.com/v2/projects?page=2" ``` Some endpoints also allow a custom page size by using the `per_page` parameter: ``` $ curl -u EMAIL_OR_ACCESS_TOKEN "https://api.phrase.com/v2/projects?page=2&per_page=50" ``` Unless specified otherwise in the description of the respective endpoint, `per_page` allows you to specify a page size up to 100 items. ## Link-Headers We provide you with pagination URLs in the [Link Header field](http://tools.ietf.org/html/rfc5988). Make use of this information to avoid building pagination URLs yourself. The Link-Header is only available on GET requests that return a list of resources. It contains URLs for the first, previous, next, and last pages of results. ``` Link: ; rel="first", ; rel="prev", ; rel="next", ; rel="last" ``` Possible `rel` values are: | Value | Description | | ----- | ----------------------------------- | | next | URL of the next page of results | | last | URL of the last page of results | | first | URL of the first page of results | | prev | URL of the previous page of results | ## Rate Limiting All API endpoints are subject to rate limiting to ensure good performance for all customers. The rate limit is calculated per user: * 1000 requests per 5 minutes * 4 concurrent (parallel) requests For your convenience we send information on the current rate limit within the response headers: | Header | Description | | ---------------------- | --------------------------------------------------------- | | X-Rate-Limit-Limit | Number of max requests allowed in the current time period | | X-Rate-Limit-Remaining | Number of remaining requests in the current time period | | X-Rate-Limit-Reset | Timestamp of end of current time period as UNIX timestamp | If you should run into the rate limit, you will receive the HTTP status code `429: Too many requests`. If you should need higher rate limits, [contact us](https://phrase.com/contact). ## Conditional GET requests / HTTP Caching Note: Conditional GET requests are currently only supported for `locales#download` and `translations#index` We will return an ETag or Last-Modified header with most GET requests. When you request a resource we recommend to store this value and submit them on subsequent requests as `If-Modified-Since` and `If-None-Match` headers. If the resource has not changed in the meantime, we will return the status `304 Not Modified` instead of rendering and returning the resource again. In most cases this is less time-consuming and makes your application/integration faster. Please note that all conditional requests that return a response with status 304 don't count against your rate limits. ``` $ curl -i -u EMAIL_OR_ACCESS_TOKEN "https://api.phrase.com/v2/projects/1234abcd1234abcdefefabcd1234efab/locales/en/download" HTTP/1.1 200 OK ETag: "abcd1234abcdefefabcd1234efab1234" Last-Modified: Wed, 28 Jan 2015 15:31:30 UTC Status: 200 OK $ curl -i -u EMAIL_OR_ACCESS_TOKEN "https://api.phrase.com/v2/projects/1234abcd1234abcdefefabcd1234efab/locales/en/download" -H 'If-None-Match: "abcd1234abcdefefabcd1234efab1234"' HTTP/1.1 304 Not Modified ETag: "abcd1234abcdefefabcd1234efab1234" Last-Modified: Wed, 28 Jan 2015 15:31:30 UTC Status: 304 Not Modified $ curl -i -u EMAIL_OR_ACCESS_TOKEN "https://api.phrase.com/v2/projects/1234abcd1234abcdefefabcd1234efab/locales/en/download" -H "If-Modified-Since: Wed, 28 Jan 2015 15:31:30 UTC" HTTP/1.1 304 Not Modified Last-Modified: Wed, 28 Jan 2015 15:31:30 UTC Status: 304 Not Modified ``` # Usage examples Source: https://developers.phrase.com/en/api/strings/usage-examples Learn how to filter translations and keys, verify translations in bulk, manage tags, and upload Excel files using the Phrase Strings API v2. Learn how to work more efficiently with Phrase Strings API v2 with these workflow-oriented examples. Most examples use the `q` parameter, which accepts a qualifier-based search syntax. Qualifiers let you filter keys and translations by tag, verification status, date range, and more. Qualifiers can be combined in a single query string (space-separated). Note that search results are drawn from an index and may lag behind recent writes by a few minutes on large projects. Use these examples as starting points for bulk operations such as verifying, tagging, or exporting filtered subsets of your localization data. > To authenticate, pass your access token in the `Authorization` header. See [Authentication](https://developers.phrase.com/en/api/strings/authentication) for how to obtain a token. ## Find excluded translations with a certain content ``` GET /v2/projects/:project_id/translations ``` List excluded translations for the given project which start with the term `PhraseApp`. ### Parameters | Name | Type | Description | | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sort` *(optional)* | `string` | Sort criteria. Can be one of: `key_name`, `created_at`, `updated_at`.
**Default:** `key_name` | | `order` *(optional)* | `string` | Order direction. Can be one of: `asc`, `desc`.
**Default:** `asc` | | `q` *(optional)* | `string` | Specify a query to find translations by content (including wildcards).
**Note:** Search is limited to 10,000 results and may not include recently updated data (depending on the project size).

Supported qualifiers:
- `id:translation_id,...` – comma-separated list of IDs
- `tags:XYZ` – tag on the translation
- `unverified:{true\|false}` – verification status
- `reviewed:{true\|false}` – reviewed status
- `excluded:{true\|false}` – exclusion status
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – date range queries
| ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/translations?sort=updated_at&order=desc&q=PhraseApp*%20excluded:true" \ -H "Authorization: token YOUR_ACCESS_TOKEN" ``` ``` phrase translations list \ --project_id \ --sort updated_at \ --order desc \ --query 'PhraseApp* excluded:true' \ --access_token ``` **Response (200 OK)** ```json theme={null} [ { "id": "abcd1234abcd1234abcd1234abcd1234", "content": "PhraseApp welcome message", "unverified": false, "excluded": true, "plural_suffix": "", "key": { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "home.welcome" }, "locale": { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "en-US", "code": "en-US" }, "created_at": "2015-01-28T09:52:53Z", "updated_at": "2015-01-28T09:52:53Z" } ] ``` ## Find unverified translations with a certain content ``` GET /v2/projects/:project_id/translations ``` List unverified translations for the given project which start with the term `PhraseApp` and are not verified. ### Parameters | Name | Type | Description | | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sort` *(optional)* | `string` | Sort criteria. Can be one of: `key_name`, `created_at`, `updated_at`.
**Default:** `key_name` | | `order` *(optional)* | `string` | Order direction. Can be one of: `asc`, `desc`.
**Default:** `asc` | | `q` *(optional)* | `string` | Specify a query to find translations by content (including wildcards).

**Note:** Search is limited to 10,000 results and may not include recently updated data (depending on the project size).

Supported qualifiers:
- `id:translation_id,...` – comma-separated list of IDs
- `tags:XYZ` – tag on the translation
- `unverified:{true\|false}` – verification status
- `reviewed:{true\|false}` – reviewed status
- `excluded:{true\|false}` – exclusion status
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – date range queries | ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/translations?sort=updated_at&order=desc&q=PhraseApp*%20unverified:true" \ -H "Authorization: token YOUR_ACCESS_TOKEN" ``` ``` phrase translations list \ --project_id \ --sort updated_at \ --order desc \ --query 'PhraseApp* unverified:true' \ --access_token ``` **Response (200 OK)** ```json theme={null} [ { "id": "abcd1234abcd1234abcd1234abcd1234", "content": "PhraseApp welcome message", "unverified": true, "excluded": false, "plural_suffix": "", "key": { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "home.welcome" }, "locale": { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "en-US", "code": "en-US" }, "created_at": "2015-01-28T09:52:53Z", "updated_at": "2015-01-28T09:52:53Z" } ] ``` ## Verify translations selected by query ``` PATCH /v2/projects/:project_id/translations/verify ``` Verify all translations that are matching the query `my dog`. ### Parameters | Name | Type | Description | | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `q` *(optional)* | `string` | Specify a query to find translations by content (including wildcards).

**Note:** Search is limited to 10,000 results and may not include recently updated data (depending on the project size).

Supported qualifiers:
- `id:translation_id,...` – comma-separated list of IDs
- `tags:XYZ` – tag on the translation
- `unverified:{true\|false}` – verification status
- `reviewed:{true\|false}` – reviewed status
- `excluded:{true\|false}` – exclusion status
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – date range queries
| | `sort` *(optional)* | `string` | Sort criteria. Can be one of: `key_name`, `created_at`, `updated_at`.
**Default:** `key_name` | | `order` *(optional)* | `string` | Order direction. Can be one of: `asc`, `desc`.
**Default:** `asc` | ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/translations/verify" \ -H "Authorization: token YOUR_ACCESS_TOKEN" \ -X PATCH \ -d '{"q":"my dog unverified:true","sort":"updated_at","order":"desc"}' \ -H 'Content-Type: application/json' ``` ``` phrase translations verify \ --project_id \ --data '{"query":""my dog unverified:true"", "sort":"updated_at", "order":"desc"}' \ --access_token ``` **Response (200 OK)** ```json theme={null} { "records_affected": 23 } ``` ## Find recently updated keys ``` GET /v2/projects/:project_id/keys ``` Find updated keys with with the `updated_at` qualifier like `updated_at:>=2013-02-21T00:00:00Z`. This example returns keys that have been updated on or after 2013-02-21. ### Parameters | Name | Type | Description | | ------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sort` *(optional)* | `string` | Sort by field. Can be one of: `name`, `created_at`, `updated_at`.
**Default:** `name` | | `order` *(optional)* | `string` | Order direction. Can be one of: `asc`, `desc`.
**Default:** `asc` | | `q` *(optional)* | `string` | Specify a query to do broad search for keys by name (including wildcards).

Supported qualifiers:
- `ids:key_id,...` – queries on a comma-separated list of IDs
- `name:key_name,...` – exact key names (comma-separated, escape spaces/commas/colons with `\\`)
- `tags:tag_name,...` – filter for keys with certain tags
- `uploads:upload_id,...` – filter for keys with certain uploads
- `job:{true\|false}` – filter for keys mentioned in a job
- `translated:{true\|false}` – requires `locale_id`
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – date range filtering
- `unmentioned_in_upload:upload_id` – keys not mentioned in given upload | | `locale_id` *(optional)* | `string` | Locale used to determine the translation state of a key when filtering for untranslated or translated keys. | ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/keys?sort=updated_at&order=desc&q=updated_at:%3E=2013-02-21T00:00:00Z&locale_id=abcd1234abcd1234abcd1234abcd1234" \ -H "Authorization: token YOUR_ACCESS_TOKEN" ``` ``` phrase keys list \ --project_id \ --sort updated_at \ --order desc \ --query "updated_at:>=2013-02-21T00:00:00Z" \ --locale_id abcd1234abcd1234abcd1234abcd1234 \ --access_token ``` **Response (200 OK)** ```json theme={null} [ { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "home.welcome", "created_at": "2013-02-21T08:00:00Z", "updated_at": "2024-01-15T10:30:00Z", "tags": ["landing-page"] } ] ``` ## Find keys with a certain tag ``` GET /v2/projects/:project_id/keys ``` Keys with certain tags can be filtered with the qualifier `tags:`. ### Parameters | Name | Type | Description | | ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `q` *(optional)* | `string` | Specify a query to do broad search for keys by name (including wildcards).

Supported qualifiers:
- `ids:key_id,...` – queries on a comma-separated list of IDs
- `name:key_name,...` – exact key names (comma-separated, escape spaces/commas/colons with `\\`)
- `tags:tag_name,...` – filter for keys with certain tags
- `uploads:upload_id,...` – filter for keys with certain uploads
- `job:{true\|false}` – filter for keys mentioned in an active job
- `translated:{true\|false}` – requires `locale_id`
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – filter by date
- `unmentioned_in_upload:upload_id` – filter keys unmentioned in a specific upload
| ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/keys?q=tags:admin" \ -H "Authorization: token YOUR_ACCESS_TOKEN" ``` ``` phrase keys list \ --project_id \ --query "tags:admin" \ --access_token ``` **Response (200 OK)** ```json theme={null} [ { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "admin.dashboard.title", "tags": ["admin"], "created_at": "2015-01-28T09:52:53Z", "updated_at": "2024-01-15T10:30:00Z" } ] ``` ## Add tags to collection of keys ``` PATCH /v2/projects/:project_id/keys/tag ``` Add the tags `landing-page` and `release-1.2` to all keys that start with `dog` and are translated in the locale `abcd1234abcd1234abcd1234abcd1234`. ### Parameters | Name | Type | Description | | ------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `q` *(optional)* | `string` | Specify a query to do broad search for keys by name (including wildcards).

Supported qualifiers:
- `ids:key_id,...` – queries on a comma-separated list of IDs
- `name:key_name,...` – exact key names (comma-separated, escape spaces/commas/colons with `\\`)
- `tags:tag_name,...` – filter for keys with certain tags
- `uploads:upload_id,...` – filter for keys with certain uploads
- `job:{true\|false}` – filter for keys mentioned in an active job
- `translated:{true\|false}` – requires `locale_id`
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – filter by date
- `unmentioned_in_upload:upload_id` – filter keys unmentioned in a specific upload
| | `tags` | `string` | **Required.** Tag or comma-separated list of tags to add to the matching collection of keys | | `locale_id` *(optional)* | `string` | Locale used to determine the translation state of a key when filtering for untranslated or translated keys. | ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/keys/tag" \ -H "Authorization: token YOUR_ACCESS_TOKEN" \ -X PATCH \ -d '{"q":"dog* translated:true","tags":"landing-page,release-1.2","locale_id":"abcd1234abcd1234abcd1234abcd1234"}' \ -H 'Content-Type: application/json' ``` ``` phrase keys tag \ --project_id \ --data '{"query":"'dog* translated:true'", "tags":"landing-page,release-1.2", "locale_id":"abcd1234abcd1234abcd1234abcd1234"}' \ --access_token ``` **Response (200 OK)** ```json theme={null} { "records_affected": 5 } ``` ## Remove tags from collection of keys ``` PATCH /v2/projects/:project_id/keys/untag ``` Remove the tags `landing-page` and `release-1.2` from all keys that start with `dog` and are translated in the locale `abcd1234abcd1234abcd1234abcd1234`. ### Parameters | Name | Type | Description | | ------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `q` *(optional)* | `string` | Specify a query to do broad search for keys by name (including wildcards).

Supported qualifiers:
- `ids:key_id,...` – queries on a comma-separated list of IDs
- `name:key_name,...` – exact key names (comma-separated, escape spaces/commas/colons with `\\`)
- `tags:tag_name,...` – filter for keys with certain tags
- `uploads:upload_id,...` – filter for keys with certain uploads
- `job:{true\|false}` – filter for keys mentioned in an active job
- `translated:{true\|false}` – requires `locale_id`
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – filter by date
- `unmentioned_in_upload:upload_id` – filter keys unmentioned in a specific upload
| | `tags` | `string` | **Required.** Tag or comma-separated list of tags to remove from the matching collection of keys | | `locale_id` *(optional)* | `string` | Locale used to determine the translation state of a key when filtering for untranslated or translated keys. | ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/keys/untag" \ -H "Authorization: token YOUR_ACCESS_TOKEN" \ -X PATCH \ -d '{"q":"dog* translated:true","tags":"landing-page,release-1.2","locale_id":"abcd1234abcd1234abcd1234abcd1234"}' \ -H 'Content-Type: application/json' ``` ``` phrase keys untag \ --project_id \ --data '{"query":"'dog* translated:true'", "tags":"landing-page,release-1.2", "locale_id":"abcd1234abcd1234abcd1234abcd1234"}' \ --access_token ``` **Response (200 OK)** ```json theme={null} { "records_affected": 5 } ``` ## Find keys with broad text match ``` GET /v2/projects/:project_id/keys ``` Example query `my dog`. ### Parameters | Name | Type | Description | | ---------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `q` *(optional)* | `string` | Specify a query to do broad search for keys by name (including wildcards).

Supported qualifiers:
- `ids:key_id,...` – queries on a comma-separated list of IDs
- `name:key_name,...` – exact key names (comma-separated, escape spaces/commas/colons with `\\`)
- `tags:tag_name,...` – filter for keys with certain tags
- `uploads:upload_id,...` – filter for keys with certain uploads
- `job:{true\|false}` – filter for keys mentioned in an active job
- `translated:{true\|false}` – requires `locale_id`
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – date range filter
- `unmentioned_in_upload:upload_id` – keys not mentioned in specific upload | ### Matches **My dog** is lazy **my dog** is lazy angry **dog** in **my** house ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/keys?q=my%20dog" \ -H "Authorization: token YOUR_ACCESS_TOKEN" ``` ``` phrase keys list \ --project_id \ --query "my dog" \ --access_token ``` **Response (200 OK)** ```json theme={null} [ { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "my.dog.is.lazy", "tags": [], "created_at": "2015-01-28T09:52:53Z", "updated_at": "2024-01-15T10:30:00Z" } ] ``` ## Find keys with exact text match ``` GET /v2/projects/:project_id/keys ``` Example query `"my dog is lazy"` (note backslashes before any whitespace character in the example query) ### Parameters | Name | Type | Description | | ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `q` *(optional)* | `string` | Specify a query to do broad search for keys by name (including wildcards).

Supported qualifiers:
- `ids:key_id,...` – queries on a comma-separated list of IDs
- `name:key_name,...` – exact key names (comma-separated, escape spaces/commas/colons with `\\`)
- `tags:tag_name,...` – filter for keys with certain tags
- `uploads:upload_id,...` – filter for keys with certain uploads
- `job:{true\|false}` – filter for keys mentioned in an active job
- `translated:{true\|false}` – requires `locale_id` to be specified
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – date range queries
- `unmentioned_in_upload:upload_id` – filter keys unmentioned within upload | ### Matches ~~My dog is lazy~~ my dog is lazy ~~angry dog in my house~~ ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/keys?q=name:my%5C%20dog%5C%20is%5C%20lazy" \ -H "Authorization: token YOUR_ACCESS_TOKEN" ``` ``` phrase keys list \ --project_id \ --query "name:my\ dog\ is\ lazy" \ --access_token ``` **Response (200 OK)** ```json theme={null} [ { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "my.dog.is.lazy", "tags": [], "created_at": "2015-01-28T09:52:53Z", "updated_at": "2024-01-15T10:30:00Z" } ] ``` ## Find keys with wildcard character matching ``` GET /v2/projects/:project_id/keys ``` Example query `*dog is*` ### Parameters | Name | Type | Description | | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `q` *(optional)* | `string` | Specify a query to do broad search for keys by name (including wildcards).

The following qualifiers are supported in the search term:
- `ids:key_id,...` – queries on a comma-separated list of IDs
- `name:key_name,...` – exact key names (comma-separated; escape spaces, commas, and colons with `\\`)
- `tags:tag_name,...` – filter for keys with certain tags
- `uploads:upload_id,...` – filter for keys with certain uploads
- `job:{true\|false}` – filter for keys mentioned in an active job
- `translated:{true\|false}` – filter by translation status (requires `locale_id`)
- `updated_at:{>=\|<=}2013-02-21T00:00:00Z` – filter by date range
- `unmentioned_in_upload:upload_id` – filter keys unmentioned within specific upload | ### Matches My **dog is** lazy my **dog is** lazy ~~angry dog in my house~~ ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/keys?q=*dog%20is*" \ -H "Authorization: token YOUR_ACCESS_TOKEN" ``` ``` phrase keys list \ --project_id \ --query '*dog is*' \ --access_token ``` **Response (200 OK)** ```json theme={null} [ { "id": "abcd1234abcd1234abcd1234abcd1234", "name": "my.dog.is.lazy", "tags": [], "created_at": "2015-01-28T09:52:53Z", "updated_at": "2024-01-15T10:30:00Z" } ] ``` ## Upload an Excel file with several translations ``` POST /v2/projects/:project_id/uploads ``` Suppose you have an excel file where the 'A' column contains the key names, the 'B' column contains English translations, the 'C' column contains German translations and the 'D' column contains comments. Furthermore, the actual content starts in the second row, since the first row is reserved for a header. You can upload this file and import all translations at once! ### Parameters | Name | Type | Description | | ----------------------------------- | -------- | ------------------------------------------------------------------------- | | `file` | `file` | **Required.** File to be imported | | `file_format` | `string` | **Required.** File format. Auto-detected when possible and not specified. | | `locale_mapping[en]` | `string` | Name of the column containing translations for locale `en`. | | `locale_mapping[de]` | `string` | Name of the column containing translations for locale `de`. | | `format_options[comment_column]` | `string` | Name of the column containing descriptions for keys. | | `format_options[tag_column]` | `string` | Name of the column containing tags for keys. | | `format_options[key_name_column]` | `string` | Name of the column containing the names of the keys. | | `format_options[first_content_row]` | `string` | Name of the first row containing actual translations. | ### Example Request ```bash theme={null} curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/uploads" \ -H "Authorization: token YOUR_ACCESS_TOKEN" \ -X POST \ -F file=@/path/to/my/file.xlsx \ -F file_format=xlsx \ -F locale_mapping[en]=B \ -F locale_mapping[de]=C \ -F format_options[comment_column]=D \ -F format_options[tag_column]=E \ -F format_options[key_name_column]=A \ -F format_options[first_content_row]=2 ``` ``` phrase uploads create \ --project_id \ --file /path/to/my/file.xlsx \ --file_format xlsx \ --locale_id abcd1234cdef1234abcd1234cdef1234 \ --tags awesome-feature,needs-proofreading \ --locale_mapping '{"en": "B", "de": "C"}' \ --format_options '{"comment_column": "D", "tag_column": "E", "key_name_column": "A", "first_content_row": "2"}' \ --access_token ``` **Response (200 OK)** ```json theme={null} { "id": "abcd1234abcd1234abcd1234abcd1234", "filename": "file.xlsx", "format": "xlsx", "state": "success", "summary": { "translation_keys_created": 10, "translation_keys_updated": 2, "translation_keys_unmentioned": 0, "translations_created": 20, "translations_updated": 4 }, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:05Z" } ``` ## Errors | Status | Code | Cause | Remediation | | ------ | ---------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------- | | 400 | `bad_request` | Malformed query string or invalid qualifier in `q` parameter. | Check the qualifier syntax; ensure date values use ISO 8601 format. | | 401 | `unauthorized` | Missing or invalid access token. | Pass a valid token via `Authorization: token `. | | 403 | `forbidden` | The token does not have access to the specified project. | Verify the token has read/write access to the project. | | 404 | `not_found` | The specified `project_id` does not exist or is not accessible. | Confirm the project ID is correct and the token has project access. | | 422 | `unprocessable_entity` | Required parameter missing (e.g., `tags` not provided for tag operations). | Include all required parameters in the request body. | # Home Source: https://developers.phrase.com/en/home

Phrase Developer Hub

Explore our guides and examples to integrate Phrase.

Explore the Phrase APIs

Phrase offers a suite of APIs to help you manage localization at scale - from translating dynamic content to integrating with your translation workflows.
} href="/en/api/platform/introduction"> Phrase Platform related APIs serving unified authorization experience to all Phrase Platform products. } href="/en/api/strings/introduction"> As a string management platform for key-based translations, Phrase Strings extracts segments of words from code repositories or design files to manage the entire translation process. } href="/en/api/tms/latest/introduction"> The leading translation management system that automates, translates, and manages content with intelligence and at scale. } href="/en/api/language-ai/introduction"> Our sophisticated, secure and scalable AI translation tool capabilities including MT and LLM aggregation, selection and quality assessment. } href="/en/api/studio/introduction"> AI-powered audio and video processing for transcription, translation, and dubbing. Process content in over 100 languages with advanced features like glossaries and pronunciations. } href="/en/api/connectors/introduction"> A tool for building custom flows using Phrase Integrations. Easily connect localization processes with external systems and extend built-in integrations with your own functionality. } href="/en/api/quality-evaluator/latest/introduction"> Automatically assess translation quality using LLM-powered checks resolved from Style Guide Rules and Content Groups. } href="/en/api/style-guides/introduction"> Manage organization-wide writing guidelines that keep translations and authored content on-brand. Upload Markdown style guides per language and version every revision. } href="/en/api/control-hub/introduction"> Organize and connect platform objects into content groups for coordinated workflows across Phrase products.
# Create a new invitation Source: https://developers.phrase.com/en/api/strings/invitations/create-a-new-invitation /openapi/phrase-strings.json post /accounts/{account_id}/invitations Invite a person to an account. Developers and translators need `project_ids` and `locale_ids` assigned to access them. Access token scope must include `team.manage`. # Delete an invitation Source: https://developers.phrase.com/en/api/strings/invitations/delete-an-invitation /openapi/phrase-strings.json delete /accounts/{account_id}/invitations/{id} Delete an existing invitation (must not be accepted yet). Access token scope must include `team.manage`. # Get a single invitation Source: https://developers.phrase.com/en/api/strings/invitations/get-a-single-invitation /openapi/phrase-strings.json get /accounts/{account_id}/invitations/{id} Get details on a single invitation. Access token scope must include `team.manage`. # List invitations Source: https://developers.phrase.com/en/api/strings/invitations/list-invitations /openapi/phrase-strings.json get /accounts/{account_id}/invitations List invitations for an account. It will also list the accessible resources like projects and locales the invited user has access to. In case nothing is shown the default access from the role is used. Access token scope must include `team.manage`. # Resend an invitation Source: https://developers.phrase.com/en/api/strings/invitations/resend-an-invitation /openapi/phrase-strings.json post /accounts/{account_id}/invitations/{id}/resend Resend the invitation email (must not be accepted yet). Access token scope must include `team.manage`. # Update a member's invitation access Source: https://developers.phrase.com/en/api/strings/invitations/update-a-members-invitation-access /openapi/phrase-strings.json patch /projects/{project_id}/invitations/{id} Update member's settings in the invitations. Access token scope must include `team.manage`. # Update an invitation Source: https://developers.phrase.com/en/api/strings/invitations/update-an-invitation /openapi/phrase-strings.json patch /accounts/{account_id}/invitations/{id} Update an existing invitation (must not be accepted yet). The `email` cannot be updated. Developers and translators need `project_ids` and `locale_ids` assigned to access them. Access token scope must include `team.manage`. # Create/Update a job annotation Source: https://developers.phrase.com/en/api/strings/job-annotations/createupdate-a-job-annotation /openapi/phrase-strings.json patch /projects/{project_id}/jobs/{job_id}/annotations/{id} Create or update an annotation for a job. If the annotation already exists, it will be updated; otherwise, a new annotation will be created. # Create/Update a job locale annotation Source: https://developers.phrase.com/en/api/strings/job-annotations/createupdate-a-job-locale-annotation /openapi/phrase-strings.json patch /projects/{project_id}/jobs/{job_id}/locales/{job_locale_id}/annotations/{id} Create or update an annotation for a job locale. If the annotation already exists, it will be updated; otherwise, a new annotation will be created. # Delete a job annotation Source: https://developers.phrase.com/en/api/strings/job-annotations/delete-a-job-annotation /openapi/phrase-strings.json delete /projects/{project_id}/jobs/{job_id}/annotations/{id} Delete an annotation for a job. # Delete a job locale annotation Source: https://developers.phrase.com/en/api/strings/job-annotations/delete-a-job-locale-annotation /openapi/phrase-strings.json delete /projects/{project_id}/jobs/{job_id}/locales/{job_locale_id}/annotations/{id} Delete an annotation for a job locale. # List job annotations Source: https://developers.phrase.com/en/api/strings/job-annotations/list-job-annotations /openapi/phrase-strings.json get /projects/{project_id}/jobs/{job_id}/annotations Retrieve a list of annotations for a job. # List job locale annotations Source: https://developers.phrase.com/en/api/strings/job-annotations/list-job-locale-annotations /openapi/phrase-strings.json get /projects/{project_id}/jobs/{job_id}/locales/{job_locale_id}/annotations Retrieve a list of annotations for a job locale. # Create a job comment Source: https://developers.phrase.com/en/api/strings/job-comments/create-a-job-comment /openapi/phrase-strings.json post /projects/{project_id}/jobs/{job_id}/comments Create a new comment for a job. # Delete a job comment Source: https://developers.phrase.com/en/api/strings/job-comments/delete-a-job-comment /openapi/phrase-strings.json delete /projects/{project_id}/jobs/{job_id}/comments/{id} Delete an existing job comment. # Get a single job comment Source: https://developers.phrase.com/en/api/strings/job-comments/get-a-single-job-comment /openapi/phrase-strings.json get /projects/{project_id}/jobs/{job_id}/comments/{id} Get details on a single job comment. # List job comments Source: https://developers.phrase.com/en/api/strings/job-comments/list-job-comments /openapi/phrase-strings.json get /projects/{project_id}/jobs/{job_id}/comments List all comments for a job. # Update a job comment Source: https://developers.phrase.com/en/api/strings/job-comments/update-a-job-comment /openapi/phrase-strings.json patch /projects/{project_id}/jobs/{job_id}/comments/{id} Update an existing job comment. # Add a target locale to a job Source: https://developers.phrase.com/en/api/strings/job-locales/add-a-target-locale-to-a-job /openapi/phrase-strings.json post /projects/{project_id}/jobs/{job_id}/locales Adds a target locale to a job. # Complete a job locale Source: https://developers.phrase.com/en/api/strings/job-locales/complete-a-job-locale /openapi/phrase-strings.json post /projects/{project_id}/jobs/{job_id}/locales/{id}/complete Mark a job locale as completed. # List job target locales Source: https://developers.phrase.com/en/api/strings/job-locales/list-job-target-locales /openapi/phrase-strings.json get /projects/{project_id}/jobs/{job_id}/locales List all target locales for a given job. # Remove a target locale from a job Source: https://developers.phrase.com/en/api/strings/job-locales/remove-a-target-locale-from-a-job /openapi/phrase-strings.json delete /projects/{project_id}/jobs/{job_id}/locales/{id} Removes a target locale from a job. # Reopen a job locale Source: https://developers.phrase.com/en/api/strings/job-locales/reopen-a-job-locale /openapi/phrase-strings.json post /projects/{project_id}/jobs/{job_id}/locales/{id}/reopen Mark a job locale as uncompleted. # Review a job locale Source: https://developers.phrase.com/en/api/strings/job-locales/review-a-job-locale /openapi/phrase-strings.json post /projects/{project_id}/jobs/{job_id}/locales/{id}/complete_review Mark job locale as reviewed. # Show single job target locale Source: https://developers.phrase.com/en/api/strings/job-locales/show-single-job-target-locale /openapi/phrase-strings.json get /projects/{project_id}/jobs/{job_id}/locales/{id} Get a single target locale for a given job. # Update a job target locale Source: https://developers.phrase.com/en/api/strings/job-locales/update-a-job-target-locale /openapi/phrase-strings.json patch /projects/{project_id}/jobs/{job_id}/locales/{id} Update an existing job target locale. # Create a job template locale Source: https://developers.phrase.com/en/api/strings/job-template-locales/create-a-job-template-locale /openapi/phrase-strings.json post /projects/{project_id}/job_templates/{job_template_id}/locales Create a new job template locale. # Delete a job template locale Source: https://developers.phrase.com/en/api/strings/job-template-locales/delete-a-job-template-locale /openapi/phrase-strings.json delete /projects/{project_id}/job_templates/{job_template_id}/locales/{job_template_locale_id} Delete an existing job template locale. # Get a single job template locale Source: https://developers.phrase.com/en/api/strings/job-template-locales/get-a-single-job-template-locale /openapi/phrase-strings.json get /projects/{project_id}/job_templates/{job_template_id}/locales/{job_template_locale_id} Get a single job template locale for a given job template. # List job template locales Source: https://developers.phrase.com/en/api/strings/job-template-locales/list-job-template-locales /openapi/phrase-strings.json get /projects/{project_id}/job_templates/{job_template_id}/locales List all job template locales for a given job template. # Update a job template locale Source: https://developers.phrase.com/en/api/strings/job-template-locales/update-a-job-template-locale /openapi/phrase-strings.json patch /projects/{project_id}/job_templates/{job_template_id}/locales/{job_template_locale_id} Update an existing job template locale. # Create a job template Source: https://developers.phrase.com/en/api/strings/job-templates/create-a-job-template /openapi/phrase-strings.json post /projects/{project_id}/job_templates Create a new job template. # Delete a job template Source: https://developers.phrase.com/en/api/strings/job-templates/delete-a-job-template /openapi/phrase-strings.json delete /projects/{project_id}/job_templates/{id} Delete an existing job template. # Get a single job template Source: https://developers.phrase.com/en/api/strings/job-templates/get-a-single-job-template /openapi/phrase-strings.json get /projects/{project_id}/job_templates/{id} Get details on a single job template for a given project. # List job templates Source: https://developers.phrase.com/en/api/strings/job-templates/list-job-templates /openapi/phrase-strings.json get /projects/{project_id}/job_templates List all job templates for the given project. # Update a job template Source: https://developers.phrase.com/en/api/strings/job-templates/update-a-job-template /openapi/phrase-strings.json patch /projects/{project_id}/job_templates/{id} Update an existing job template. # Add keys to job Source: https://developers.phrase.com/en/api/strings/jobs/add-keys-to-job /openapi/phrase-strings.json post /projects/{project_id}/jobs/{id}/keys Add multiple keys to a existing job. # Complete a job Source: https://developers.phrase.com/en/api/strings/jobs/complete-a-job /openapi/phrase-strings.json post /projects/{project_id}/jobs/{id}/complete Mark a job as completed. # Create a job Source: https://developers.phrase.com/en/api/strings/jobs/create-a-job /openapi/phrase-strings.json post /projects/{project_id}/jobs Create a new job. # Delete a job Source: https://developers.phrase.com/en/api/strings/jobs/delete-a-job /openapi/phrase-strings.json delete /projects/{project_id}/jobs/{id} Delete an existing job. # Get a single job Source: https://developers.phrase.com/en/api/strings/jobs/get-a-single-job /openapi/phrase-strings.json get /projects/{project_id}/jobs/{id} Get details on a single job for a given project. # List account jobs Source: https://developers.phrase.com/en/api/strings/jobs/list-account-jobs /openapi/phrase-strings.json get /accounts/{account_id}/jobs List all jobs for the given account. # List jobs Source: https://developers.phrase.com/en/api/strings/jobs/list-jobs /openapi/phrase-strings.json get /projects/{project_id}/jobs List all jobs for the given project. # Lock a job Source: https://developers.phrase.com/en/api/strings/jobs/lock-a-job /openapi/phrase-strings.json post /projects/{project_id}/jobs/{id}/lock If you are the job owner, you may lock a job using this API request. # Remove keys from job Source: https://developers.phrase.com/en/api/strings/jobs/remove-keys-from-job /openapi/phrase-strings.json delete /projects/{project_id}/jobs/{id}/keys Remove multiple keys from existing job. # Reopen a job Source: https://developers.phrase.com/en/api/strings/jobs/reopen-a-job /openapi/phrase-strings.json post /projects/{project_id}/jobs/{id}/reopen Mark a job as uncompleted. # Start a job Source: https://developers.phrase.com/en/api/strings/jobs/start-a-job /openapi/phrase-strings.json post /projects/{project_id}/jobs/{id}/start Starts an existing job in state draft. # Unlock a job Source: https://developers.phrase.com/en/api/strings/jobs/unlock-a-job /openapi/phrase-strings.json post /projects/{project_id}/jobs/{id}/unlock If you are the job owner, you may unlock a locked job using this API request. # Update a job Source: https://developers.phrase.com/en/api/strings/jobs/update-a-job /openapi/phrase-strings.json patch /projects/{project_id}/jobs/{id} Update an existing job. # List format annotations for a key Source: https://developers.phrase.com/en/api/strings/key-format-annotations/list-format-annotations-for-a-key /openapi/phrase-strings.json get /projects/{project_id}/keys/{id}/format_annotations Returns the format annotations stored on a translation key. Format annotations capture file-format data recorded when the key was imported — for example, an ARB placeholder block or an XLIFF note. Results are limited to 1,000 entries. # Attach the Figma attachment to a key Source: https://developers.phrase.com/en/api/strings/keys-figma-attachments/attach-the-figma-attachment-to-a-key /openapi/phrase-strings.json post /projects/{project_id}/figma_attachments/{figma_attachment_id}/keys Attach the Figma attachment to a key # Detach the Figma attachment from a key Source: https://developers.phrase.com/en/api/strings/keys-figma-attachments/detach-the-figma-attachment-from-a-key /openapi/phrase-strings.json delete /projects/{project_id}/figma_attachments/{figma_attachment_id}/keys/{id} Detach the Figma attachment from a key # Add tags to collection of keys Source: https://developers.phrase.com/en/api/strings/keys/add-tags-to-collection-of-keys /openapi/phrase-strings.json patch /projects/{project_id}/keys/tag Tags all keys matching query. Same constraints as list. # Create a key Source: https://developers.phrase.com/en/api/strings/keys/create-a-key /openapi/phrase-strings.json post /projects/{project_id}/keys Create a new key. # Delete a key Source: https://developers.phrase.com/en/api/strings/keys/delete-a-key /openapi/phrase-strings.json delete /projects/{project_id}/keys/{id} Delete an existing key. # Delete collection of keys Source: https://developers.phrase.com/en/api/strings/keys/delete-collection-of-keys /openapi/phrase-strings.json delete /projects/{project_id}/keys Delete all keys matching query. Same constraints as list. Please limit the number of affected keys to about 1,000 as you might experience timeouts otherwise. # Exclude a locale on a collection of keys Source: https://developers.phrase.com/en/api/strings/keys/exclude-a-locale-on-a-collection-of-keys /openapi/phrase-strings.json patch /projects/{project_id}/keys/exclude Exclude a locale on keys matching query. Same constraints as list. # Get a single key Source: https://developers.phrase.com/en/api/strings/keys/get-a-single-key /openapi/phrase-strings.json get /projects/{project_id}/keys/{id} Get details on a single key for a given project. # Include a locale on a collection of keys Source: https://developers.phrase.com/en/api/strings/keys/include-a-locale-on-a-collection-of-keys /openapi/phrase-strings.json patch /projects/{project_id}/keys/include Include a locale on keys matching query. Same constraints as list. # List keys Source: https://developers.phrase.com/en/api/strings/keys/list-keys /openapi/phrase-strings.json get /projects/{project_id}/keys List all keys for the given project. Alternatively you can POST requests to /search. # Remove tags from collection of keys Source: https://developers.phrase.com/en/api/strings/keys/remove-tags-from-collection-of-keys /openapi/phrase-strings.json patch /projects/{project_id}/keys/untag Removes specified tags from keys matching query. # Search keys Source: https://developers.phrase.com/en/api/strings/keys/search-keys /openapi/phrase-strings.json post /projects/{project_id}/keys/search Search keys for the given project matching query. # Update a key Source: https://developers.phrase.com/en/api/strings/keys/update-a-key /openapi/phrase-strings.json patch /projects/{project_id}/keys/{id} Update an existing key. # Batch unlink child keys from a parent key Source: https://developers.phrase.com/en/api/strings/linked-keys/batch-unlink-child-keys-from-a-parent-key /openapi/phrase-strings.json delete /projects/{project_id}/keys/{id}/key_links Removes one or more child keys from a parent key's linked-key group, or dissolves the entire group by setting unlink_parent to true. Use this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content). This operation is only available on main projects. It returns 422 when a child key in `child_key_ids` is not currently linked to the parent, or when a translation update fails while unlinking. # Link child keys to a parent key Source: https://developers.phrase.com/en/api/strings/linked-keys/link-child-keys-to-a-parent-key /openapi/phrase-strings.json post /projects/{project_id}/keys/{id}/key_links Designates a translation key as a parent and links one or more child keys to it. Once linked, child keys receive a special reference marker as their translation content, signalling that their translations are derived from the parent. Use this when you want to group related keys — for example, a short label and its long-form variant — so translators see them in context together. Pass an empty child_key_ids array to mark the key as a parent without linking any children yet. Both the parent key and every child key must belong to the main project; branch keys cannot participate in key links. A child key can have at most one parent at a time; attempting to link a child that already has a parent returns a 422 error with code CHILD_IS_ALREADY_LINKED. Parent and child key plurality must match — linking a plural child to a non-plural parent (or vice versa) also returns a 422. # List child keys of a parent key Source: https://developers.phrase.com/en/api/strings/linked-keys/list-child-keys-of-a-parent-key /openapi/phrase-strings.json get /projects/{project_id}/keys/{id}/key_links Returns the key link record for a parent key, including all child keys associated with it. Key linking lets translation keys share translations — a child key inherits content from its designated parent. Use this endpoint to inspect which keys are linked under a given parent before unlinking them or auditing translation consistency across related keys. The key identified by `id` must be designated as a parent key (it must have at least one child key linked to it). Listing the links of a key that is not a parent returns 400. # Unlink a child key from a parent key Source: https://developers.phrase.com/en/api/strings/linked-keys/unlink-a-child-key-from-a-parent-key /openapi/phrase-strings.json delete /projects/{project_id}/keys/{id}/key_links/{child_key_id} Removes a single child key from a parent key's link group. A link group is the relationship model that keeps child keys synchronized with a parent: while linked, a child key's translations are derived from the parent's content. When you call this endpoint, the child key leaves the group and becomes independent — its existing translations are updated with the parent's current content and then marked unverified, signalling that reviewers should confirm the content is still appropriate for the child's context. Use this endpoint when you need to detach one specific child key while keeping other children linked. To detach multiple children at once, use the batch unlink endpoint. This operation is only available on main projects. It returns 422 when the child key is not currently linked to the specified parent key, or when a translation update fails during the unlink process. # Initiate async download of a locale Source: https://developers.phrase.com/en/api/strings/locale-downloads/initiate-async-download-of-a-locale /openapi/phrase-strings.json post /projects/{project_id}/locales/{locale_id}/downloads Prepare a locale for download in a specific file format. # Show status of an async locale download Source: https://developers.phrase.com/en/api/strings/locale-downloads/show-status-of-an-async-locale-download /openapi/phrase-strings.json get /projects/{project_id}/locales/{locale_id}/downloads/{id} Show status of already started async locale download. If the download is finished, the download link will be returned. # Create a locale Source: https://developers.phrase.com/en/api/strings/locales/create-a-locale /openapi/phrase-strings.json post /projects/{project_id}/locales Create a new locale. # Delete a locale Source: https://developers.phrase.com/en/api/strings/locales/delete-a-locale /openapi/phrase-strings.json delete /projects/{project_id}/locales/{id} Delete an existing locale. # Download a locale Source: https://developers.phrase.com/en/api/strings/locales/download-a-locale /openapi/phrase-strings.json get /projects/{project_id}/locales/{id}/download Download a locale in a specific file format. # Get a single locale Source: https://developers.phrase.com/en/api/strings/locales/get-a-single-locale /openapi/phrase-strings.json get /projects/{project_id}/locales/{id} Get details on a single locale for a given project. # List locales Source: https://developers.phrase.com/en/api/strings/locales/list-locales /openapi/phrase-strings.json get /projects/{project_id}/locales List all locales for the given project. # List locales used in account Source: https://developers.phrase.com/en/api/strings/locales/list-locales-used-in-account /openapi/phrase-strings.json get /accounts/{id}/locales List all locales unique by locale code used across all projects within an account. # Update a locale Source: https://developers.phrase.com/en/api/strings/locales/update-a-locale /openapi/phrase-strings.json patch /projects/{project_id}/locales/{id} Update an existing locale. # Get single member Source: https://developers.phrase.com/en/api/strings/members/get-single-member /openapi/phrase-strings.json get /accounts/{account_id}/members/{id} Get details on a single user in the account. Access token scope must include `team.manage`. # List members Source: https://developers.phrase.com/en/api/strings/members/list-members /openapi/phrase-strings.json get /accounts/{account_id}/members Get all users active in the account. It also lists resources like projects and locales the member has access to. In case nothing is shown the default access from the role is used. Access token scope must include `team.manage`. # Remove a user from the account Source: https://developers.phrase.com/en/api/strings/members/remove-a-user-from-the-account /openapi/phrase-strings.json delete /accounts/{account_id}/members/{id} Remove a user from the account. The user will be removed from the account but not deleted from Phrase. Access token scope must include `team.manage`. # Update a member Source: https://developers.phrase.com/en/api/strings/members/update-a-member /openapi/phrase-strings.json patch /accounts/{account_id}/members/{id} Update user permissions in the account. Developers and translators need `project_ids` and `locale_ids` assigned to access them. Access token scope must include `team.manage`. # Update a member's project settings Source: https://developers.phrase.com/en/api/strings/members/update-a-members-project-settings /openapi/phrase-strings.json patch /projects/{project_id}/members/{id} Update user settings in the project. Access token scope must include `team.manage`. # List notification groups Source: https://developers.phrase.com/en/api/strings/notification-groups/list-notification-groups /openapi/phrase-strings.json get /notification_groups List all notification groups from the current user # Mark a notification group as read Source: https://developers.phrase.com/en/api/strings/notification-groups/mark-a-notification-group-as-read /openapi/phrase-strings.json patch /notification_groups/{id}/mark_as_read Mark a notifications group of the current user as read # Mark all notification groups as read Source: https://developers.phrase.com/en/api/strings/notification-groups/mark-all-notification-groups-as-read /openapi/phrase-strings.json patch /notification_groups/mark_all_as_read Mark all notification groups of the current user as read # Get a single notification Source: https://developers.phrase.com/en/api/strings/notifications/get-a-single-notification /openapi/phrase-strings.json get /notifications/{id} Get details on a single notification. # List notifications Source: https://developers.phrase.com/en/api/strings/notifications/list-notifications /openapi/phrase-strings.json get /notifications List all notifications from the current user # Mark all notifications as read Source: https://developers.phrase.com/en/api/strings/notifications/mark-all-notifications-as-read /openapi/phrase-strings.json post /notifications/mark_all_as_read Mark all notifications of the current user as read # Cancel an order Source: https://developers.phrase.com/en/api/strings/orders/cancel-an-order /openapi/phrase-strings.json delete /projects/{project_id}/orders/{id} Cancel an existing order. Must not yet be confirmed. # Confirm an order Source: https://developers.phrase.com/en/api/strings/orders/confirm-an-order /openapi/phrase-strings.json patch /projects/{project_id}/orders/{id}/confirm Confirm an existing order and send it to the provider for translation. Same constraints as for create. # Create a new order Source: https://developers.phrase.com/en/api/strings/orders/create-a-new-order /openapi/phrase-strings.json post /projects/{project_id}/orders Create a new order. Access token scope must include `orders.create`. # Get a single order Source: https://developers.phrase.com/en/api/strings/orders/get-a-single-order /openapi/phrase-strings.json get /projects/{project_id}/orders/{id} Get details on a single order. # List orders Source: https://developers.phrase.com/en/api/strings/orders/list-orders /openapi/phrase-strings.json get /projects/{project_id}/orders List all orders for the given project. # Create an organization job template locale Source: https://developers.phrase.com/en/api/strings/organization-job-template-locales/create-an-organization-job-template-locale /openapi/phrase-strings.json post /accounts/{account_id}/job_templates/{job_template_id}/locales Create a new organization job template locale. # Delete an organization job template locale Source: https://developers.phrase.com/en/api/strings/organization-job-template-locales/delete-an-organization-job-template-locale /openapi/phrase-strings.json delete /accounts/{account_id}/job_templates/{job_template_id}/locales/{job_template_locale_id} Delete an existing organization job template locale. # Get a single organization job template locale Source: https://developers.phrase.com/en/api/strings/organization-job-template-locales/get-a-single-organization-job-template-locale /openapi/phrase-strings.json get /accounts/{account_id}/job_templates/{job_template_id}/locales/{job_template_locale_id} Get a single job template locale for a given organization job template. # List organization job template locales Source: https://developers.phrase.com/en/api/strings/organization-job-template-locales/list-organization-job-template-locales /openapi/phrase-strings.json get /accounts/{account_id}/job_templates/{job_template_id}/locales List all job template locales for a given organization job template. # Update an organization job template locale Source: https://developers.phrase.com/en/api/strings/organization-job-template-locales/update-an-organization-job-template-locale /openapi/phrase-strings.json patch /accounts/{account_id}/job_templates/{job_template_id}/locales/{job_template_locale_id} Update an existing organization job template locale. # Create an organization job template Source: https://developers.phrase.com/en/api/strings/organization-job-templates/create-an-organization-job-template /openapi/phrase-strings.json post /accounts/{account_id}/job_templates Create a new organization job template. # Get a single organization job template Source: https://developers.phrase.com/en/api/strings/organization-job-templates/get-a-single-organization-job-template /openapi/phrase-strings.json get /accounts/{account_id}/job_templates/{id} Get details on a single organization job template for a given account. # List organization job templates Source: https://developers.phrase.com/en/api/strings/organization-job-templates/list-organization-job-templates /openapi/phrase-strings.json get /accounts/{account_id}/job_templates List all job templates for the given account. # Delete an organization job template Source: https://developers.phrase.com/en/api/strings/organization-job-templates/delete-an-organization-job-template /openapi/phrase-strings.json delete /accounts/{account_id}/job_templates/{id} Delete an existing organization job template. # Update an organization job template Source: https://developers.phrase.com/en/api/strings/organization-job-templates/update-an-organization-job-template /openapi/phrase-strings.json patch /accounts/{account_id}/job_templates/{id} Update an existing organization job template. # Create a pre-translation job Source: https://developers.phrase.com/en/api/strings/pre-translations/create-a-pre-translation-job /openapi/phrase-strings.json post /projects/{project_id}/pre_translations Triggers a pre-translation job for a resource within a project, addressed by `translatable_type` (`locale`, `job`, `translation_key`, or `upload`) and `translatable_id` (its ID). Enqueues machine translation using the project's configured MT engine. # Get a single pre-translation job Source: https://developers.phrase.com/en/api/strings/pre-translations/get-a-single-pre-translation-job /openapi/phrase-strings.json get /projects/{project_id}/pre_translations/{id} Returns a single pre-translation job identified by its ID. # List pre-translation jobs Source: https://developers.phrase.com/en/api/strings/pre-translations/list-pre-translation-jobs /openapi/phrase-strings.json get /projects/{project_id}/pre_translations Returns all pre-translation jobs scoped to a project, ordered by creation date descending. # Create a project Source: https://developers.phrase.com/en/api/strings/projects/create-a-project /openapi/phrase-strings.json post /projects Create a new project in the given account. When `source_project_id` is supplied, the new project is created as a clone of that project. All locales, keys, and translations are copied asynchronously after the response is returned, so they may not be available immediately. Settings from the source project are inherited unless explicitly overridden in the request; in clone mode, the `shares_translation_memory` field is ignored and inherited from the source. `shares_translation_memory` defaults to `true` when omitted on a non-clone create. # Delete a project Source: https://developers.phrase.com/en/api/strings/projects/delete-a-project /openapi/phrase-strings.json delete /projects/{id} Delete an existing project. Associated repository syncs and OTA distributions are removed. A `project:delete` event is dispatched. # Get a single project Source: https://developers.phrase.com/en/api/strings/projects/get-a-single-project /openapi/phrase-strings.json get /projects/{id} Get details on a single project. # List projects Source: https://developers.phrase.com/en/api/strings/projects/list-projects /openapi/phrase-strings.json get /projects List all projects the current user has access to. When the `account_id` query parameter is omitted, the response includes projects across every account the user is a member of. Pass `account_id` to scope the results to a single account. # Update a project Source: https://developers.phrase.com/en/api/strings/projects/update-a-project /openapi/phrase-strings.json patch /projects/{id} Update an existing project. # Get Translation Quality Source: https://developers.phrase.com/en/api/strings/quality-performance-score/get-translation-quality /openapi/phrase-strings.json post /projects/{project_id}/quality_performance_score Retrieves the quality scores for your Strings translations. Returns a score, measured by Phrase QPS # Create a release trigger Source: https://developers.phrase.com/en/api/strings/release-triggers/create-a-release-trigger /openapi/phrase-strings.json post /accounts/{account_id}/distributions/{distribution_id}/release_triggers Create a new recurring release. New releases will be published automatically, based on the cron schedule provided. Currently, only one release trigger can exist per distribution. # Delete a single release trigger Source: https://developers.phrase.com/en/api/strings/release-triggers/delete-a-single-release-trigger /openapi/phrase-strings.json delete /accounts/{account_id}/distributions/{distribution_id}/release_triggers/{id} Delete a single release trigger. # Get a single release trigger Source: https://developers.phrase.com/en/api/strings/release-triggers/get-a-single-release-trigger /openapi/phrase-strings.json get /accounts/{account_id}/distributions/{distribution_id}/release_triggers/{id} Get details of a single release trigger. # List release triggers Source: https://developers.phrase.com/en/api/strings/release-triggers/list-release-triggers /openapi/phrase-strings.json get /accounts/{account_id}/distributions/{distribution_id}/release_triggers List all release triggers for the given distribution. Note: Currently only one release trigger can exist per distribution. # Update a release trigger Source: https://developers.phrase.com/en/api/strings/release-triggers/update-a-release-trigger /openapi/phrase-strings.json patch /accounts/{account_id}/distributions/{distribution_id}/release_triggers/{id} Update a recurring release. # Create a release Source: https://developers.phrase.com/en/api/strings/releases/create-a-release /openapi/phrase-strings.json post /accounts/{account_id}/distributions/{distribution_id}/releases Create a new release. # Delete a release Source: https://developers.phrase.com/en/api/strings/releases/delete-a-release /openapi/phrase-strings.json delete /accounts/{account_id}/distributions/{distribution_id}/releases/{id} Delete an existing release. # Get a single release Source: https://developers.phrase.com/en/api/strings/releases/get-a-single-release /openapi/phrase-strings.json get /accounts/{account_id}/distributions/{distribution_id}/releases/{id} Get details on a single release. # List releases Source: https://developers.phrase.com/en/api/strings/releases/list-releases /openapi/phrase-strings.json get /accounts/{account_id}/distributions/{distribution_id}/releases List all releases for the given distribution. # Publish a release Source: https://developers.phrase.com/en/api/strings/releases/publish-a-release /openapi/phrase-strings.json post /accounts/{account_id}/distributions/{distribution_id}/releases/{id}/publish Publish a release for production. # Update a release Source: https://developers.phrase.com/en/api/strings/releases/update-a-release /openapi/phrase-strings.json patch /accounts/{account_id}/distributions/{distribution_id}/releases/{id} Update an existing release. # Get a single Repo Sync Event Source: https://developers.phrase.com/en/api/strings/repo-sync-events/get-a-single-repo-sync-event /openapi/phrase-strings.json get /accounts/{account_id}/repo_syncs/{repo_sync_id}/events/{id} Shows a single Repo Sync event. # Repository Syncs History Source: https://developers.phrase.com/en/api/strings/repo-sync-events/repository-syncs-history /openapi/phrase-strings.json get /accounts/{account_id}/repo_syncs/{id}/events Get the history of a single Repo Sync. The history includes all imports and exports performed by the Repo Sync. # Activate a Repo Sync Source: https://developers.phrase.com/en/api/strings/repo-syncs/activate-a-repo-sync /openapi/phrase-strings.json post /accounts/{account_id}/repo_syncs/{id}/activate Activate a deactivated Repo Sync. Active syncs can be used to import and export translations, and imports to Phrase are automatically triggered by pushes to the repository, if configured. # Create a Repo Sync Source: https://developers.phrase.com/en/api/strings/repo-syncs/create-a-repo-sync /openapi/phrase-strings.json post /accounts/{account_id}/repo_syncs Create a new Repo Sync. # Deactivate a Repo Sync Source: https://developers.phrase.com/en/api/strings/repo-syncs/deactivate-a-repo-sync /openapi/phrase-strings.json post /accounts/{account_id}/repo_syncs/{id}/deactivate Deactivate an active Repo Sync. Import and export can't be performed on deactivated syncs and the pushes to the repository won't trigger the import to Phrase. # Export to code repository Source: https://developers.phrase.com/en/api/strings/repo-syncs/export-to-code-repository /openapi/phrase-strings.json post /accounts/{account_id}/repo_syncs/{id}/export Export translations from Phrase Strings to repository provider according to the .phrase.yml file within the code repository. *Export is done asynchronously and may take several seconds depending on the project size.* # Get a single Repo Sync Source: https://developers.phrase.com/en/api/strings/repo-syncs/get-a-single-repo-sync /openapi/phrase-strings.json get /accounts/{account_id}/repo_syncs/{id} Shows a single Repo Sync setting. # Get Repo Syncs Source: https://developers.phrase.com/en/api/strings/repo-syncs/get-repo-syncs /openapi/phrase-strings.json get /accounts/{account_id}/repo_syncs Lists all Repo Syncs from an account # Import from code repository Source: https://developers.phrase.com/en/api/strings/repo-syncs/import-from-code-repository /openapi/phrase-strings.json post /accounts/{account_id}/repo_syncs/{id}/import Import translations from repository provider to Phrase Strings according to the .phrase.yml file within the code repository. _Import is done asynchronously and may take several seconds depending on the project size._ # Get Project Report Source: https://developers.phrase.com/en/api/strings/reports/get-project-report /openapi/phrase-strings.json get /projects/{project_id}/report Get report of a single project. # List Locale Reports Source: https://developers.phrase.com/en/api/strings/reports/list-locale-reports /openapi/phrase-strings.json get /projects/{project_id}/report/locales List all locale reports for the given project # Create a screenshot marker Source: https://developers.phrase.com/en/api/strings/screenshot-markers/create-a-screenshot-marker /openapi/phrase-strings.json post /projects/{project_id}/screenshots/{screenshot_id}/markers Create a new screenshot marker. # Delete a screenshot marker Source: https://developers.phrase.com/en/api/strings/screenshot-markers/delete-a-screenshot-marker /openapi/phrase-strings.json delete /projects/{project_id}/screenshots/{screenshot_id}/markers Delete an existing screenshot marker. # Get a single screenshot marker Source: https://developers.phrase.com/en/api/strings/screenshot-markers/get-a-single-screenshot-marker /openapi/phrase-strings.json get /projects/{project_id}/screenshots/{screenshot_id}/markers/{id} Get details on a single screenshot marker for a given project. # List screenshot markers Source: https://developers.phrase.com/en/api/strings/screenshot-markers/list-screenshot-markers /openapi/phrase-strings.json get /projects/{project_id}/screenshots/{id}/markers List all screenshot markers for the given project. # Update a screenshot marker Source: https://developers.phrase.com/en/api/strings/screenshot-markers/update-a-screenshot-marker /openapi/phrase-strings.json patch /projects/{project_id}/screenshots/{screenshot_id}/markers Update an existing screenshot marker. # Create a screenshot Source: https://developers.phrase.com/en/api/strings/screenshots/create-a-screenshot /openapi/phrase-strings.json post /projects/{project_id}/screenshots Creates a screenshot in a project to provide visual context for in-context translation. Attach translation keys to regions of the uploaded image so translators can see where each string appears in your UI. This endpoint accepts a multipart/form-data request with a binary file upload, unlike most Phrase API endpoints that use JSON. Use a multipart form client or the -F flag in curl rather than a JSON body. The screenshot name must be unique within the project (case-insensitive). When name is omitted, it is derived from the uploaded filename. The account must have the Screenshots feature enabled; requests to projects on accounts without it return 403. Creating a screenshot requires a token with the write scope and manage access to the project. # Delete a screenshot Source: https://developers.phrase.com/en/api/strings/screenshots/delete-a-screenshot /openapi/phrase-strings.json delete /projects/{project_id}/screenshots/{id} Permanently removes a screenshot and all its associated markers from the project. Use this when you need to fully remove a screenshot that is no longer relevant — for example, after a UI redesign renders the captured screen obsolete. This is a hard delete: the screenshot record and every key-to-region marker linked to it are destroyed together and cannot be recovered. # Get a single screenshot Source: https://developers.phrase.com/en/api/strings/screenshots/get-a-single-screenshot /openapi/phrase-strings.json get /projects/{project_id}/screenshots/{id} Returns a single screenshot belonging to the specified project. Use this to retrieve the screenshot's name, description, hosted image URL, and marker count after uploading, or before creating, updating, or inspecting its markers. The response is a synchronous, idempotent read — repeated calls return the same record without side effects. The Attachable Screenshots feature must be enabled on the account. # List screenshots Source: https://developers.phrase.com/en/api/strings/screenshots/list-screenshots /openapi/phrase-strings.json get /projects/{project_id}/screenshots List all screenshots for the given project. # Update a screenshot Source: https://developers.phrase.com/en/api/strings/screenshots/update-a-screenshot /openapi/phrase-strings.json patch /projects/{project_id}/screenshots/{id} Update an existing screenshot. # Search across projects Source: https://developers.phrase.com/en/api/strings/search/search-across-projects /openapi/phrase-strings.json post /accounts/{account_id}/search Search for keys and translations in all account projects *Note: Search is limited to 10000 results and may not include recently updated data depending on the project sizes.* # Add Project to Space Source: https://developers.phrase.com/en/api/strings/spaces/add-project-to-space /openapi/phrase-strings.json post /accounts/{account_id}/spaces/{space_id}/projects Adds an existing project to the space. # Create a Space Source: https://developers.phrase.com/en/api/strings/spaces/create-a-space /openapi/phrase-strings.json post /accounts/{account_id}/spaces Create a new Space. # Delete Space Source: https://developers.phrase.com/en/api/strings/spaces/delete-space /openapi/phrase-strings.json delete /accounts/{account_id}/spaces/{id} Delete the specified Space. # Get Space Source: https://developers.phrase.com/en/api/strings/spaces/get-space /openapi/phrase-strings.json get /accounts/{account_id}/spaces/{id} Show the specified Space. # List Projects in Space Source: https://developers.phrase.com/en/api/strings/spaces/list-projects-in-space /openapi/phrase-strings.json get /accounts/{account_id}/spaces/{space_id}/projects List all projects for the specified Space. # List Spaces Source: https://developers.phrase.com/en/api/strings/spaces/list-spaces /openapi/phrase-strings.json get /accounts/{account_id}/spaces List all Spaces for the given account. # Remove Project from Space Source: https://developers.phrase.com/en/api/strings/spaces/remove-project-from-space /openapi/phrase-strings.json delete /accounts/{account_id}/spaces/{space_id}/projects/{id} Removes a specified project from the specified space. # Update Space Source: https://developers.phrase.com/en/api/strings/spaces/update-space /openapi/phrase-strings.json patch /accounts/{account_id}/spaces/{id} Update the specified Space. # Create a style guide Source: https://developers.phrase.com/en/api/strings/style-guides/create-a-style-guide /openapi/phrase-strings.json post /projects/{project_id}/styleguides Create a new style guide. # Delete a style guide Source: https://developers.phrase.com/en/api/strings/style-guides/delete-a-style-guide /openapi/phrase-strings.json delete /projects/{project_id}/styleguides/{id} Delete an existing style guide. # Get a single style guide Source: https://developers.phrase.com/en/api/strings/style-guides/get-a-single-style-guide /openapi/phrase-strings.json get /projects/{project_id}/styleguides/{id} Get details on a single style guide. # List style guides Source: https://developers.phrase.com/en/api/strings/style-guides/list-style-guides /openapi/phrase-strings.json get /projects/{project_id}/styleguides List all styleguides for the given project. # Update a style guide Source: https://developers.phrase.com/en/api/strings/style-guides/update-a-style-guide /openapi/phrase-strings.json patch /projects/{project_id}/styleguides/{id} Update an existing style guide. # Create a tag Source: https://developers.phrase.com/en/api/strings/tags/create-a-tag /openapi/phrase-strings.json post /projects/{project_id}/tags Create a new tag. # Delete a tag Source: https://developers.phrase.com/en/api/strings/tags/delete-a-tag /openapi/phrase-strings.json delete /projects/{project_id}/tags/{name} Delete an existing tag. # Get a single tag Source: https://developers.phrase.com/en/api/strings/tags/get-a-single-tag /openapi/phrase-strings.json get /projects/{project_id}/tags/{name} Get details and progress information on a single tag for a given project. # List tags Source: https://developers.phrase.com/en/api/strings/tags/list-tags /openapi/phrase-strings.json get /projects/{project_id}/tags List all tags for the given project. # Add Project to Team Source: https://developers.phrase.com/en/api/strings/teams/add-project-to-team /openapi/phrase-strings.json post /accounts/{account_id}/teams/{team_id}/projects Adds an existing project to the team. # Add Space Source: https://developers.phrase.com/en/api/strings/teams/add-space /openapi/phrase-strings.json post /accounts/{account_id}/teams/{team_id}/spaces Adds an existing space to the team. # Add User Source: https://developers.phrase.com/en/api/strings/teams/add-user /openapi/phrase-strings.json post /accounts/{account_id}/teams/{team_id}/users Adds an existing user to the team. # Create a Team Source: https://developers.phrase.com/en/api/strings/teams/create-a-team /openapi/phrase-strings.json post /accounts/{account_id}/teams Create a new Team. # Delete Team Source: https://developers.phrase.com/en/api/strings/teams/delete-team /openapi/phrase-strings.json delete /accounts/{account_id}/teams/{id} Delete the specified Team. # Get Team Source: https://developers.phrase.com/en/api/strings/teams/get-team /openapi/phrase-strings.json get /accounts/{account_id}/teams/{id} Show the specified Team. # List Teams Source: https://developers.phrase.com/en/api/strings/teams/list-teams /openapi/phrase-strings.json get /accounts/{account_id}/teams List all Teams for the given account. # Remove Project from Team Source: https://developers.phrase.com/en/api/strings/teams/remove-project-from-team /openapi/phrase-strings.json delete /accounts/{account_id}/teams/{team_id}/projects/{id} Removes a specified project from the specified team. # Remove Space Source: https://developers.phrase.com/en/api/strings/teams/remove-space /openapi/phrase-strings.json delete /accounts/{account_id}/teams/{team_id}/spaces/{id} Removes a specified space from the specified team. # Remove User Source: https://developers.phrase.com/en/api/strings/teams/remove-user /openapi/phrase-strings.json delete /accounts/{account_id}/teams/{team_id}/users/{id} Removes a specified user from the specified team. # Update Team Source: https://developers.phrase.com/en/api/strings/teams/update-team /openapi/phrase-strings.json patch /accounts/{account_id}/teams/{id} Update the specified Team. # Create a translation Source: https://developers.phrase.com/en/api/strings/translations/create-a-translation /openapi/phrase-strings.json post /projects/{project_id}/translations Create a translation. # Exclude a translation from export Source: https://developers.phrase.com/en/api/strings/translations/exclude-a-translation-from-export /openapi/phrase-strings.json patch /projects/{project_id}/translations/{id}/exclude Set exclude from export flag on an existing translation. # Exclude translations by query Source: https://developers.phrase.com/en/api/strings/translations/exclude-translations-by-query /openapi/phrase-strings.json patch /projects/{project_id}/translations/exclude Exclude translations matching query from locale export. # Get a single translation Source: https://developers.phrase.com/en/api/strings/translations/get-a-single-translation /openapi/phrase-strings.json get /projects/{project_id}/translations/{id} Get details on a single translation. # Include a translation Source: https://developers.phrase.com/en/api/strings/translations/include-a-translation /openapi/phrase-strings.json patch /projects/{project_id}/translations/{id}/include Remove exclude from export flag from an existing translation. # Include translations by query Source: https://developers.phrase.com/en/api/strings/translations/include-translations-by-query /openapi/phrase-strings.json patch /projects/{project_id}/translations/include Include translations matching query in locale export. # List all translations Source: https://developers.phrase.com/en/api/strings/translations/list-all-translations /openapi/phrase-strings.json get /projects/{project_id}/translations List translations for the given project. If you want to download all translations for one locale we recommend to use the `locales#download` endpoint. # List translations by key Source: https://developers.phrase.com/en/api/strings/translations/list-translations-by-key /openapi/phrase-strings.json get /projects/{project_id}/keys/{key_id}/translations List translations for a specific key. # List translations by locale Source: https://developers.phrase.com/en/api/strings/translations/list-translations-by-locale /openapi/phrase-strings.json get /projects/{project_id}/locales/{locale_id}/translations List translations for a specific locale. If you want to download all translations for one locale we recommend to use the `locales#download` endpoint. # Mark a translation as unverified Source: https://developers.phrase.com/en/api/strings/translations/mark-a-translation-as-unverified /openapi/phrase-strings.json patch /projects/{project_id}/translations/{id}/unverify Mark an existing translation as unverified. # Review a translation Source: https://developers.phrase.com/en/api/strings/translations/review-a-translation /openapi/phrase-strings.json patch /projects/{project_id}/translations/{id}/review Mark an existing translation as reviewed. # Review translations selected by query Source: https://developers.phrase.com/en/api/strings/translations/review-translations-selected-by-query /openapi/phrase-strings.json patch /projects/{project_id}/translations/review Review translations matching query. # Search translations Source: https://developers.phrase.com/en/api/strings/translations/search-translations /openapi/phrase-strings.json post /projects/{project_id}/translations/search Search translations for the given project. Provides the same search interface as `translations#index` but allows POST requests to avoid limitations imposed by GET requests. If you want to download all translations for one locale we recommend to use the `locales#download` endpoint. # Unreview a translation Source: https://developers.phrase.com/en/api/strings/translations/unreview-a-translation /openapi/phrase-strings.json patch /projects/{project_id}/translations/{id}/unreview Mark a reviewed translation as translated. # Unreview translations selected by query Source: https://developers.phrase.com/en/api/strings/translations/unreview-translations-selected-by-query /openapi/phrase-strings.json patch /projects/{project_id}/translations/unreview Unreview translations matching query. # Unverify translations by query Source: https://developers.phrase.com/en/api/strings/translations/unverify-translations-by-query /openapi/phrase-strings.json patch /projects/{project_id}/translations/unverify Mark translations matching query as unverified. # Update a translation Source: https://developers.phrase.com/en/api/strings/translations/update-a-translation /openapi/phrase-strings.json patch /projects/{project_id}/translations/{id} Update an existing translation. # Verify a translation Source: https://developers.phrase.com/en/api/strings/translations/verify-a-translation /openapi/phrase-strings.json patch /projects/{project_id}/translations/{id}/verify Verify an existing translation. # Verify translations by query Source: https://developers.phrase.com/en/api/strings/translations/verify-translations-by-query /openapi/phrase-strings.json patch /projects/{project_id}/translations/verify Verify translations matching query. # Create upload batch Source: https://developers.phrase.com/en/api/strings/upload-batches/create-upload-batch /openapi/phrase-strings.json post /projects/{project_id}/upload_batches Groups multiple file uploads into a single batch. Optionally, launches the deletion of unmentioned translation keys after all uploads in the batch are completed. # Get a single upload Source: https://developers.phrase.com/en/api/strings/uploads/get-a-single-upload /openapi/phrase-strings.json get /projects/{project_id}/uploads/{id} View details and summary for a single upload. # List uploads Source: https://developers.phrase.com/en/api/strings/uploads/list-uploads /openapi/phrase-strings.json get /projects/{project_id}/uploads List all uploads for the given project. # Upload a new file Source: https://developers.phrase.com/en/api/strings/uploads/upload-a-new-file /openapi/phrase-strings.json post /projects/{project_id}/uploads Upload a new language file. Creates necessary resources in your project. Note: be aware of [upload limits](https://support.phrase.com/hc/en-us/articles/8548271212188-Phrase-Strings-Limits#file-size-upload-limits-0-0). # Show current User Source: https://developers.phrase.com/en/api/strings/users/show-current-user /openapi/phrase-strings.json get /user Show details for current User. # Create a variable Source: https://developers.phrase.com/en/api/strings/variables/create-a-variable /openapi/phrase-strings.json post /projects/{project_id}/variables Create a new variable. # Delete a variable Source: https://developers.phrase.com/en/api/strings/variables/delete-a-variable /openapi/phrase-strings.json delete /projects/{project_id}/variables/{name} Delete an existing variable. # Get a single variable Source: https://developers.phrase.com/en/api/strings/variables/get-a-single-variable /openapi/phrase-strings.json get /projects/{project_id}/variables/{name} Get details on a single variable for a given project. # List variables Source: https://developers.phrase.com/en/api/strings/variables/list-variables /openapi/phrase-strings.json get /projects/{project_id}/variables List all variables for the current project. # Update a variable Source: https://developers.phrase.com/en/api/strings/variables/update-a-variable /openapi/phrase-strings.json patch /projects/{project_id}/variables/{name} Update an existing variable. # Get a single version Source: https://developers.phrase.com/en/api/strings/versions-history/get-a-single-version /openapi/phrase-strings.json get /projects/{project_id}/translations/{translation_id}/versions/{id} Get details on a single version. # List all versions Source: https://developers.phrase.com/en/api/strings/versions-history/list-all-versions /openapi/phrase-strings.json get /projects/{project_id}/translations/{translation_id}/versions List all changes done to a given translation. # Get a single webhook delivery Source: https://developers.phrase.com/en/api/strings/webhook-deliveries/get-a-single-webhook-delivery /openapi/phrase-strings.json get /projects/{project_id}/webhooks/{webhook_id}/deliveries/{id} Get all information about a single webhook delivery for the given ID. # List webhook deliveries Source: https://developers.phrase.com/en/api/strings/webhook-deliveries/list-webhook-deliveries /openapi/phrase-strings.json get /projects/{project_id}/webhooks/{webhook_id}/deliveries List all webhook deliveries for the given webhook_id. # Redeliver a single webhook delivery Source: https://developers.phrase.com/en/api/strings/webhook-deliveries/redeliver-a-single-webhook-delivery /openapi/phrase-strings.json post /projects/{project_id}/webhooks/{webhook_id}/deliveries/{id}/redeliver Trigger an individual webhook delivery to be redelivered. # Create a webhook Source: https://developers.phrase.com/en/api/strings/webhooks/create-a-webhook /openapi/phrase-strings.json post /projects/{project_id}/webhooks Create a new webhook. # Delete a webhook Source: https://developers.phrase.com/en/api/strings/webhooks/delete-a-webhook /openapi/phrase-strings.json delete /projects/{project_id}/webhooks/{id} Delete an existing webhook. # Get a single webhook Source: https://developers.phrase.com/en/api/strings/webhooks/get-a-single-webhook /openapi/phrase-strings.json get /projects/{project_id}/webhooks/{id} Get details on a single webhook. # List webhooks Source: https://developers.phrase.com/en/api/strings/webhooks/list-webhooks /openapi/phrase-strings.json get /projects/{project_id}/webhooks List all webhooks for the given project. # Test a webhook Source: https://developers.phrase.com/en/api/strings/webhooks/test-a-webhook /openapi/phrase-strings.json post /projects/{project_id}/webhooks/{id}/test Perform a test request for a webhook. Sends a synthetic `test:event` payload to the webhook's `callback_url` and returns the webhook resource. # Update a webhook Source: https://developers.phrase.com/en/api/strings/webhooks/update-a-webhook /openapi/phrase-strings.json patch /projects/{project_id}/webhooks/{id} Update an existing webhook. # Create additional workflow step Source: https://developers.phrase.com/en/api/tms/latest/additional-workflow-step/create-additional-workflow-step /openapi/phrase-tms-latest.json post /api2/v1/additionalWorkflowSteps Requires ADMIN or PROJECT_MANAGER role with the setup-server access right. The name must be unique within the organization. Additional workflow steps represent optional custom service steps (e.g. DTP, engineering, voice-over) that can be attached to quotes. Once created, a step is referenced by name in the `additionalSteps` field when creating or updating a quote via the Quotes API, and appears in the `additionalSteps` array of the quote response. # Delete additional workflow step Source: https://developers.phrase.com/en/api/tms/latest/additional-workflow-step/delete-additional-workflow-step /openapi/phrase-tms-latest.json delete /api2/v1/additionalWorkflowSteps/{id} Requires ADMIN or PROJECT_MANAGER role with the setup-server access right. # List additional workflow steps Source: https://developers.phrase.com/en/api/tms/latest/additional-workflow-step/list-additional-workflow-steps /openapi/phrase-tms-latest.json get /api2/v1/additionalWorkflowSteps Accessible to ADMIN and PROJECT_MANAGER roles. # Create analyses by languages Source: https://developers.phrase.com/en/api/tms/latest/analysis/create-analyses-by-languages /openapi/phrase-tms-latest.json post /api2/v1/analyses/byLanguages Creates one analysis per target language (analyzeByLanguage) for the supplied jobs. Requires the CREATE analysis right (internal users). # Create analyses by providers Source: https://developers.phrase.com/en/api/tms/latest/analysis/create-analyses-by-providers /openapi/phrase-tms-latest.json post /api2/v1/analyses/byProviders Creates one analysis per provider (analyzeByLinguist) for the supplied jobs. Requires the CREATE analysis right (internal users). # Create analysis Source: https://developers.phrase.com/en/api/tms/latest/analysis/create-analysis /openapi/phrase-tms-latest.json post /api2/v2/analyses Returns created analyses - batching analyses by number of segments (api.segment.count.approximation, default 100000), in case request contains more segments than maximum (api.segment.max.count, default 300000), returns 400 bad request. # Delete analyses (batch) Source: https://developers.phrase.com/en/api/tms/latest/analysis/delete-analyses-batch /openapi/phrase-tms-latest.json delete /api2/v1/analyses/bulk When purge is true the analyses are permanently (hard) deleted. Requires the DELETE analysis right (internal users). # Delete analysis Source: https://developers.phrase.com/en/api/tms/latest/analysis/delete-analysis /openapi/phrase-tms-latest.json delete /api2/v1/analyses/{analyseUid} When purge is true the analysis is permanently (hard) deleted. Requires the DELETE analysis right (internal users). # Download analysis Source: https://developers.phrase.com/en/api/tms/latest/analysis/download-analysis /openapi/phrase-tms-latest.json get /api2/v1/analyses/{analyseUid}/download Requires the DOWNLOAD analysis right (internal or linguist users). # Edit analyses (batch) Source: https://developers.phrase.com/en/api/tms/latest/analysis/edit-analyses-batch /openapi/phrase-tms-latest.json put /api2/v2/analyses/bulk If no netRateScheme is provided in request, then netRateScheme associated with provider will be used if it exists, otherwise it will remain the same as it was. # Edit analysis Source: https://developers.phrase.com/en/api/tms/latest/analysis/edit-analysis /openapi/phrase-tms-latest.json put /api2/v2/analyses/{analyseUid} If no netRateScheme is provided in request, then netRateScheme associated with provider will be used if it exists, otherwise it will remain the same as it was. # Get analysis Source: https://developers.phrase.com/en/api/tms/latest/analysis/get-analysis /openapi/phrase-tms-latest.json get /api2/v3/analyses/{analyseUid} This API endpoint retrieves analysis results, encompassing basic information about the analysis, such as its name, assigned provider, [net rate scheme](https://support.phrase.com/hc/en-us/articles/5709665578908-Net-Rate-Schemes-TMS-), [Analysis settings](https://support.phrase.com/hc/en-us/articles/5709712007708-Analysis-TMS-) settings and a subset of [Get project](../project/get-project) information for the project the analysis belongs to. The analysis results consist of each analyzed language, presented as an item within the `analyseLanguageParts` array. Each of these items contains details regarding the analyzed [jobs](https://support.phrase.com/hc/en-us/articles/5709686763420-Jobs-TMS-), [translation memories](https://support.phrase.com/hc/en-us/articles/5709688865692-Translation-Memories-Overview) and the resultant data. The analysis results are divided into two sections: - `data` stores the raw numbers, - `discountedData` recalculates the raw numbers using the selected net rate scheme. Similar to the UI, both raw and net numbers are categorized based on their source into TM, MT, and NT categories, including repetitions where applicable. These categories are then further subdivided based on the match score. # Get analysis language part Source: https://developers.phrase.com/en/api/tms/latest/analysis/get-analysis-language-part /openapi/phrase-tms-latest.json get /api2/v1/analyses/{analyseUid}/analyseLanguageParts/{analyseLanguagePartId} Returns analysis language pair # Get jobs analysis Source: https://developers.phrase.com/en/api/tms/latest/analysis/get-jobs-analysis /openapi/phrase-tms-latest.json get /api2/v1/analyses/{analyseUid}/jobs/{jobUid} Returns job's analyse # List analyses Source: https://developers.phrase.com/en/api/tms/latest/analysis/list-analyses /openapi/phrase-tms-latest.json get /api2/v3/projects/{projectUid}/jobs/{jobUid}/analyses # List jobs of analyses Source: https://developers.phrase.com/en/api/tms/latest/analysis/list-jobs-of-analyses /openapi/phrase-tms-latest.json get /api2/v1/analyses/{analyseUid}/analyseLanguageParts/{analyseLanguagePartId}/jobs Returns list of job's analyses # Recalculate analysis Source: https://developers.phrase.com/en/api/tms/latest/analysis/recalculate-analysis /openapi/phrase-tms-latest.json post /api2/v1/analyses/recalculate Requires the RECALCULATE analysis right (internal users). # Set or remove net rate scheme for analyse Source: https://developers.phrase.com/en/api/tms/latest/analysis/set-or-remove-net-rate-scheme-for-analyse /openapi/phrase-tms-latest.json put /api2/v1/analyses/{analyseUid}/netRateScheme Sets the net rate scheme of the analysis. A null netRateScheme removes the currently associated scheme. Requires the EDIT analysis right (internal users). # Get asynchronous request Source: https://developers.phrase.com/en/api/tms/latest/async-request/get-asynchronous-request /openapi/phrase-tms-latest.json get /api2/v1/async/{asyncRequestId} This API call will return information about the specified [asynchronous request](https://support.phrase.com/hc/en-us/articles/5709706916124-API-TMS-#asynchronous-apis-0-2). Apart from basic information about the asynchronous operation such as who created it and for what action, the response will contain a subset of [Get project](../project/get-project) information. The response contains an `asyncResponse` field which will remain `null` until the async request has finished processing. If any errors occurred during processing of the request, this field will contain such errors or warnings. The `action` field identifies the type of operation. Common values relevant to the job workflow: - `IMPORT_JOB` — job file import, returned by [Create job](../job/create-job) - `PRE_TRANSLATE` — pre-translation run, returned by [Pre-translate job](../job/pre-translate-job) _Note_: It is important to keep track of the number of pending asynchronous requests as these are subject to [Phrase limits](https://support.phrase.com/hc/en-us/articles/5784117234972-Phrase-TMS-Limits#api-limits-async-requests-0-2). # Get current limits Source: https://developers.phrase.com/en/api/tms/latest/async-request/get-current-limits /openapi/phrase-tms-latest.json get /api2/v1/async/status # List pending requests Source: https://developers.phrase.com/en/api/tms/latest/async-request/list-pending-requests /openapi/phrase-tms-latest.json get /api2/v1/async API call to return a list of pending asynchronous requests. Some operations within Phrase TMS are performed [asynchronously](https://support.phrase.com/hc/en-us/articles/5784117234972-Phrase-TMS-Limits#api-limits-async-requests-0-2) and their response only serves as an acknowledgement of receipt, not an actual completion of such request. Since Phrase imposes restrictions on the number of pending asynchronous requests within an organization, this API call provides the means to check the number of such pending requests. When processing a large number of asynchronous operations, Phrase recommends periodically checking this list of pending requests in order to not receive an error code during the actual processing of the requests. _Note: Only actions triggered via the APIs are counted towards this limit, the same type of operation carried out via the UI is not taken into account. This means that even with 200 pending requests, users can still create jobs via the UI._ # Authentication Source: https://developers.phrase.com/en/api/tms/latest/authentication ## Phrase Platform API tokens Preferred method – use this for a single, consistent way to access all Phrase Platform APIs. Generate a Phrase Platform JWT token as described [here](/en/api/platform/authentication), then pass it in the `Authorization` HTTP header in every subsequent API call (`Bearer`). ## ApiToken Get a token from `auth/login` [endpoint](/en/api/tms/latest/authentication/login) and then pass it in the `Authorization` HTTP header in every subsequent API call. For more information visit our [help center](https://support.phrase.com/hc/en-us/articles/5709662181404-API-Authentication-TMS-#token-0-0). | | | | -------------------- | --------------------- | | Security Scheme Type | Header Parameter Name | | API Key | Authorization | ## OAuth2 A standard OAuth 2.0 authorization code flow. For more information visit our [help center](https://support.phrase.com/hc/en-us/articles/5709662181404-API-Authentication-TMS-#oauth-2-0-0-1). | | | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Security Scheme Type | OAuth2 | | authorizationCode OAuth Flow | **Authorization URL**: [https://cloud.memsource.com/web/oauth/authorize](https://cloud.memsource.com/web/oauth/authorize)
**Token URL**: [https://cloud.memsource.com/web/oauth/token](https://cloud.memsource.com/web/oauth/token)
**Scopes**: | # Login Source: https://developers.phrase.com/en/api/tms/latest/authentication/login /openapi/phrase-tms-latest.json post /api2/v3/auth/login # Login as another user Source: https://developers.phrase.com/en/api/tms/latest/authentication/login-as-another-user /openapi/phrase-tms-latest.json post /api2/v3/auth/loginOther Available only for admin # Login to session Source: https://developers.phrase.com/en/api/tms/latest/authentication/login-to-session /openapi/phrase-tms-latest.json post /api2/v3/auth/loginToSession Logs the user into a browser session and returns a session cookie and CSRF token rather than an API token. The login is rejected when the organization restricts authentication to SSO login. # Login with Apple refresh token Source: https://developers.phrase.com/en/api/tms/latest/authentication/login-with-apple-refresh-token /openapi/phrase-tms-latest.json post /api2/v1/auth/loginWithApple/refreshToken # Login with Apple with code Source: https://developers.phrase.com/en/api/tms/latest/authentication/login-with-apple-with-code /openapi/phrase-tms-latest.json post /api2/v1/auth/loginWithApple/code # Login with Google Source: https://developers.phrase.com/en/api/tms/latest/authentication/login-with-google /openapi/phrase-tms-latest.json post /api2/v1/auth/loginWithGoogle # Logout Source: https://developers.phrase.com/en/api/tms/latest/authentication/logout /openapi/phrase-tms-latest.json post /api2/v1/auth/logout The API token may be supplied either via the token query parameter or the Authorization header, but not both. # Refresh Apple token Source: https://developers.phrase.com/en/api/tms/latest/authentication/refresh-apple-token /openapi/phrase-tms-latest.json get /api2/v1/auth/refreshAppleToken Validates the supplied Apple refresh token and returns a refreshed Apple token response. # Who am I Source: https://developers.phrase.com/en/api/tms/latest/authentication/who-am-i /openapi/phrase-tms-latest.json get /api2/v1/auth/whoAmI Returns the currently authenticated user (the current user), including their role, username, and account details. Use this endpoint to find out who the current logged-in user is, check my role, retrieve my user profile, or look up the authenticated user. Also answers "who am I" for the logged-in user. # Call force import for automated project settings Source: https://developers.phrase.com/en/api/tms/latest/automations/call-force-import-for-automated-project-settings /openapi/phrase-tms-latest.json put /api2/v1/automatedProjects/{settingsId}/forceImport For a legacy APC, once the migration deadline has passed this endpoint responds with `403 Forbidden`. # Check remote service status for automated project settings Source: https://developers.phrase.com/en/api/tms/latest/automations/check-remote-service-status-for-automated-project-settings /openapi/phrase-tms-latest.json put /api2/v1/automatedProjects/{settingsId}/checkNow For a legacy APC, once the migration deadline has passed this endpoint responds with `403 Forbidden`. # Create automated project settings Source: https://developers.phrase.com/en/api/tms/latest/automations/create-automated-project-settings /openapi/phrase-tms-latest.json post /api2/v3/automatedProjects Creates automated project creation (APC) settings. The request fails with `400 Bad Request` when the configuration is invalid — for example when monitored folders are duplicated, exceed the allowed limit, mix different connectors or project templates, or when the connector does not support (sub)folder monitoring, and when the translation-export configuration breaks its uniqueness or combination rules (such as more than one entry for the same trigger or workflow step). If the referenced connector cannot be found, the request fails with `404 Not Found`. # Delete automated project settings Source: https://developers.phrase.com/en/api/tms/latest/automations/delete-automated-project-settings /openapi/phrase-tms-latest.json delete /api2/v1/automatedProjects/{settingsId} Deletes the automated project creation (APC) settings identified by `settingsId` and returns `204 No Content`. If the APC still has active projects, the request fails with `400 Bad Request` unless `ignoreActiveProjects` is set to `true`, in which case the APC is deleted regardless of its active projects. # Delete automated project settings in batch Source: https://developers.phrase.com/en/api/tms/latest/automations/delete-automated-project-settings-in-batch /openapi/phrase-tms-latest.json delete /api2/v1/automatedProjects/batch Deletes all automated project creation (APC) settings listed in `automatedProjectIds` and returns `204 No Content`. If any APC still has active projects, the request fails with `400 Bad Request` unless `ignoreActiveProjects` is set to `true`. If any of the supplied identifiers does not exist, the request fails with `404 Not Found`. # Get Automated Project Creation running state Source: https://developers.phrase.com/en/api/tms/latest/automations/get-automated-project-creation-running-state /openapi/phrase-tms-latest.json get /api2/v1/automatedProjects/{settingsId}/running Available only for APCs stored on the Automation Service; otherwise the request fails with `400 Bad Request`. # Get automated project creation settings by ID Source: https://developers.phrase.com/en/api/tms/latest/automations/get-automated-project-creation-settings-by-id /openapi/phrase-tms-latest.json get /api2/v3/automatedProjects/{settingsId} Returns the automated project creation (APC) settings identified by `settingsId`. For a legacy APC, once the migration deadline has passed this endpoint responds with `403 Forbidden`. # Get Automated Project Creation status data Source: https://developers.phrase.com/en/api/tms/latest/automations/get-automated-project-creation-status-data /openapi/phrase-tms-latest.json get /api2/v1/automatedProjects/{settingsId}/status Returns the current status of the automated project creation (APC) identified by `settingsId`, including its last/next check times, associated projects, monitored folder statuses, and any active `warnings`. Use this endpoint to check for connector or export delivery failures on the APC: `warnings` entries of type `NEEDS_ATTENTION` whose payload includes `affectedTranslationExportsUids` or `unreachableTranslationExportsUids` indicate jobs whose translations failed to export to the connected destination (e.g. a CMS/connector). # List automated project creation settings Source: https://developers.phrase.com/en/api/tms/latest/automations/list-automated-project-creation-settings /openapi/phrase-tms-latest.json get /api2/v1/automatedProjects # Returns files from monitored folder Source: https://developers.phrase.com/en/api/tms/latest/automations/returns-files-from-monitored-folder /openapi/phrase-tms-latest.json get /api2/v1/automatedProjects/{settingsId}/monitoredFolder/{encodedMonitoredFolder}/connectors/{connectorId}/folders/{encodedFolder} Available only for APCs stored on the Automation Service; otherwise the request fails with `400 Bad Request`. # Update automated project settings Source: https://developers.phrase.com/en/api/tms/latest/automations/update-automated-project-settings /openapi/phrase-tms-latest.json put /api2/v3/automatedProjects/{settingsId} Updates the automated project creation (APC) settings identified by `settingsId`. The request fails with `400 Bad Request` when the configuration is invalid — for example when monitored folders are duplicated, exceed the allowed limit, mix different connectors or project templates, or when the connector does not support (sub)folder monitoring, when the translation-export configuration breaks its uniqueness or combination rules, or when the continuous-project option is changed after projects have already been created from this APC. If the referenced connector cannot be found, the request fails with `404 Not Found`. For a legacy APC, once the migration deadline has passed the request responds with `403 Forbidden`. # Upload bilingual file Source: https://developers.phrase.com/en/api/tms/latest/bilingual-file/upload-bilingual-file /openapi/phrase-tms-latest.json post /api2/v2/bilingualFiles Uploads one or more bilingual files for a job and returns the updated job parts together with their project. Send the files as a multipart/form-data request using the `file` form field. ZIP archives are automatically expanded into the bilingual files they contain. A maximum of 50 files may be uploaded in a single request. The `saveToTransMemory` parameter controls whether confirmed segments are saved to the translation memory, and `setCompleted` marks the affected job parts as completed after the upload. Requires EDIT and EDIT_SEGMENT rights on the job. # Create business unit Source: https://developers.phrase.com/en/api/tms/latest/business-unit/create-business-unit /openapi/phrase-tms-latest.json post /api2/v1/businessUnits Only available when the Business Units feature is enabled for the organization. Requires the setupServer access right. Business unit names must be unique within the organization. # Delete business unit Source: https://developers.phrase.com/en/api/tms/latest/business-unit/delete-business-unit /openapi/phrase-tms-latest.json delete /api2/v1/businessUnits/{businessUnitUid} Deleting a business unit clears its reference from all projects, project templates, term bases, and translation memories. # Edit business unit Source: https://developers.phrase.com/en/api/tms/latest/business-unit/edit-business-unit /openapi/phrase-tms-latest.json put /api2/v1/businessUnits/{businessUnitUid} # Get business unit Source: https://developers.phrase.com/en/api/tms/latest/business-unit/get-business-unit /openapi/phrase-tms-latest.json get /api2/v1/businessUnits/{businessUnitUid} Only available when the Business Units feature is enabled for the organization. Requires the setupServer access right. # List business units Source: https://developers.phrase.com/en/api/tms/latest/business-unit/list-business-units /openapi/phrase-tms-latest.json get /api2/v1/businessUnits Only available when the Business Units feature is enabled for the organization. # Edit buyer Source: https://developers.phrase.com/en/api/tms/latest/buyer/edit-buyer /openapi/phrase-tms-latest.json put /api2/v1/buyers/{buyerUid} Changing the default project owner updates all project templates owned by the previous owner within this buyer's vendor organization to use the new owner. # List buyers Source: https://developers.phrase.com/en/api/tms/latest/buyer/list-buyers /openapi/phrase-tms-latest.json get /api2/v1/buyers # Create client Source: https://developers.phrase.com/en/api/tms/latest/client/create-client /openapi/phrase-tms-latest.json post /api2/v1/clients Requires the clientCreate access right for project managers. Client names must be unique within the organization. # Delete client Source: https://developers.phrase.com/en/api/tms/latest/client/delete-client /openapi/phrase-tms-latest.json delete /api2/v1/clients/{clientUid} Deleting a client also removes its contacts and business units, and clears the client reference from all projects, project templates, term bases, and translation memories. Project managers who did not create the client need the clientDeleteOther access right (default off) to delete it. # Edit client Source: https://developers.phrase.com/en/api/tms/latest/client/edit-client /openapi/phrase-tms-latest.json put /api2/v1/clients/{clientUid} Sending null for priceList or netRateScheme clears the existing association. Project managers who did not create the client need the clientEditOther access right (default off) to edit it. # Get client Source: https://developers.phrase.com/en/api/tms/latest/client/get-client /openapi/phrase-tms-latest.json get /api2/v1/clients/{clientUid} Project managers who did not create the client need the clientViewOther access right (default off) to view it. # List clients Source: https://developers.phrase.com/en/api/tms/latest/client/list-clients /openapi/phrase-tms-latest.json get /api2/v1/clients Project managers without the clientViewOther right see only clients they created. # Create connector Source: https://developers.phrase.com/en/api/tms/latest/connector/create-connector /openapi/phrase-tms-latest.json post /api2/v1/connectors Creates a connector of the specified type. A connection test is run automatically for MAGENTO and TYPO3 connector types, or whenever `connectionTest=true` is passed. For OAuth-based connectors (e.g. GitHub, GitLab, Google Drive, OneDrive), complete the three-step OAuth flow first: POST /connectorAuthData → user authorizes → POST /connectorAuthCode. Then include the resulting `code` in the request. For credential-based connectors (FTP, SFTP, GIT, Amazon S3, etc.) no OAuth flow is required. type=PHRASE connects this TMS organization to Phrase Strings (Job Sync); see the phrase* request fields below. Requires ADMIN or PROJECT_MANAGER role with the Connector setup access right. # Delete connector Source: https://developers.phrase.com/en/api/tms/latest/connector/delete-connector /openapi/phrase-tms-latest.json delete /api2/v1/connectors/{connectorId} Deletes the connector and its backend credentials. All job widget associations are removed. Requires ADMIN or PROJECT_MANAGER role with the Connector setup access right. Fails with a Bad Request response if the connector is still used in automated project creation settings. # Download file Source: https://developers.phrase.com/en/api/tms/latest/connector/download-file /openapi/phrase-tms-latest.json get /api2/v1/connectors/{connectorId}/folders/{folder}/files/{file} Download a file from a subfolder of the selected connector. Requires ADMIN, PROJECT_MANAGER, LINGUIST, or SUBMITTER role. # Download file (async) Source: https://developers.phrase.com/en/api/tms/latest/connector/download-file-async /openapi/phrase-tms-latest.json post /api2/v2/connectors/{connectorId}/folders/{folder}/files/{file} Create an asynchronous request to download a file from a (sub)folder of the selected connector. After a callback with successful response is received, prepared file can be downloaded by [Download prepared file](../connector/download-prepared-file) or [Create job from connector asynchronous download task](../job/create-job-from-connector-asynchronous-download-task). # Download prepared file Source: https://developers.phrase.com/en/api/tms/latest/connector/download-prepared-file /openapi/phrase-tms-latest.json get /api2/v2/connectors/{connectorId}/folders/{folder}/files/{file}/tasks/{taskId} Download the file by referencing successfully finished async download request [Connector - Download file (async)](../connector/download-file-async). # Generate connector oAuth state Source: https://developers.phrase.com/en/api/tms/latest/connector/generate-connector-oauth-state /openapi/phrase-tms-latest.json post /api2/v1/connectors/connectorAuthData Step 1 of 3 in the OAuth connector flow. Generates a one-time state token (returned as `state`). Pass this token to the connector's OAuth authorization URL, then call POST /connectorAuthCode with the returned code. Required for OAuth-based connector types (e.g. GitHub, GitLab, Google Drive, OneDrive). Requires ADMIN or PROJECT_MANAGER role with the Connector setup access right. # Get a connector Source: https://developers.phrase.com/en/api/tms/latest/connector/get-a-connector /openapi/phrase-tms-latest.json get /api2/v1/connectors/{connectorId} Requires ADMIN, PROJECT_MANAGER, LINGUIST, or SUBMITTER role. # Get Connector async task states. Source: https://developers.phrase.com/en/api/tms/latest/connector/get-connector-async-task-states /openapi/phrase-tms-latest.json get /api2/v1/connectorAsyncTasks Returns a page of connector async task states for the given project. When dateCreatedFrom/dateCreatedTo are not provided, the dateCreated window defaults to the last 24 hours (current time minus 24h) up to current time plus 1h. # Get connectors' authentication page url Source: https://developers.phrase.com/en/api/tms/latest/connector/get-connectors-authentication-page-url /openapi/phrase-tms-latest.json get /api2/v1/connectorAuthPage/{type} # List connectors Source: https://developers.phrase.com/en/api/tms/latest/connector/list-connectors /openapi/phrase-tms-latest.json get /api2/v1/connectors Connectors of a sunsetted type are excluded from the response and from totalCount. Requires ADMIN, PROJECT_MANAGER, LINGUIST, or SUBMITTER role. # List files in a subfolder Source: https://developers.phrase.com/en/api/tms/latest/connector/list-files-in-a-subfolder /openapi/phrase-tms-latest.json get /api2/v1/connectors/{connectorId}/folders/{folder} List files in a subfolder of the selected connector. Requires ADMIN, PROJECT_MANAGER, LINGUIST, or SUBMITTER role. # List files in root Source: https://developers.phrase.com/en/api/tms/latest/connector/list-files-in-root /openapi/phrase-tms-latest.json get /api2/v1/connectors/{connectorId}/folders List files in a root folder of the selected connector. Requires ADMIN, PROJECT_MANAGER, LINGUIST, or SUBMITTER role. # Patch connector Source: https://developers.phrase.com/en/api/tms/latest/connector/patch-connector /openapi/phrase-tms-latest.json patch /api2/v1/connectors/{connectorId} Partially updates connector credentials. Only fields included in the request body are changed. The connector type cannot be changed; a type mismatch returns 400. A connection test is run for MAGENTO and TYPO3 connector types, or when `connectionTest=true` is passed. Requires ADMIN or PROJECT_MANAGER role with the Connector setup access right. # Retrieve connector oAuth code Source: https://developers.phrase.com/en/api/tms/latest/connector/retrieve-connector-oauth-code /openapi/phrase-tms-latest.json get /api2/v1/connectors/connectorAuthCode/{code} Step 3 of 3 in the OAuth connector flow. Polls for the authorization code stored by POST /connectorAuthCode. Use the `state` token from POST /connectorAuthData as the `code` path parameter. `cancelled` is true if the user cancelled the OAuth flow. `code` is null until the OAuth provider has redirected back. Requires ADMIN, PROJECT_MANAGER, LINGUIST, or SUBMITTER role. # Store connector oAuth code Source: https://developers.phrase.com/en/api/tms/latest/connector/store-connector-oauth-code /openapi/phrase-tms-latest.json post /api2/v1/connectors/connectorAuthCode Step 2 of 3 in the OAuth connector flow. Stores the authorization code returned by the OAuth provider. Provide the `state` token from POST /connectorAuthData and the `code` from the OAuth callback. Returns 200 if the code was stored successfully, 400 if the state token is invalid or expired. Requires ADMIN or PROJECT_MANAGER role with the Connector setup access right. # Test connection of existing connector. Source: https://developers.phrase.com/en/api/tms/latest/connector/test-connection-of-existing-connector /openapi/phrase-tms-latest.json post /api2/v1/connectors/testConnection/{connectorId} Test connection for provided connector id. Requires ADMIN, PROJECT_MANAGER, LINGUIST, or SUBMITTER role. # Upload a file to a subfolder of the selected connector Source: https://developers.phrase.com/en/api/tms/latest/connector/upload-a-file-to-a-subfolder-of-the-selected-connector /openapi/phrase-tms-latest.json post /api2/v1/connectors/{connectorId}/folders/{folder} Upload a file to a subfolder of the selected connector # Upload file (async) Source: https://developers.phrase.com/en/api/tms/latest/connector/upload-file-async /openapi/phrase-tms-latest.json post /api2/v2/connectors/{connectorId}/folders/{folder}/files/{fileName}/upload Upload a file to a subfolder of the selected connector. The upload is processed asynchronously; the response contains the id of the created async task, whose status can be tracked via [Get Connector async task states](../connector/get-connector-async-task-states). # Delete LQA comment Source: https://developers.phrase.com/en/api/tms/latest/conversations/delete-lqa-comment /openapi/phrase-tms-latest.json delete /api2/v1/jobs/{jobUid}/conversations/lqas/{conversationId}/comments/{commentId} Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Delete LQA conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/delete-lqa-conversation /openapi/phrase-tms-latest.json delete /api2/v1/jobs/{jobUid}/conversations/lqas/{conversationId} Flags the LQA conversation as deleted. Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Delete plain comment Source: https://developers.phrase.com/en/api/tms/latest/conversations/delete-plain-comment /openapi/phrase-tms-latest.json delete /api2/v1/jobs/{jobUid}/conversations/plains/{conversationId}/comments/{commentId} Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Delete plain conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/delete-plain-conversation /openapi/phrase-tms-latest.json delete /api2/v1/jobs/{jobUid}/conversations/plains/{conversationId} Flags the plain conversation as deleted. Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Edit plain conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/edit-plain-conversation /openapi/phrase-tms-latest.json put /api2/v1/jobs/{jobUid}/conversations/plains/{conversationId} Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Find all conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/find-all-conversation /openapi/phrase-tms-latest.json post /api2/v1/jobs/conversations/find Returns conversations of all types across the requested jobs. Available to internal, guest and linguist users. Project managers require the EDIT right on the job; other roles require SHOW. Guests must also match the project client and have the right to view other users' projects. # Get LQA conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/get-lqa-conversation /openapi/phrase-tms-latest.json get /api2/v1/jobs/{jobUid}/conversations/lqas/{conversationId} Available to internal, guest and linguist users. Project managers require the EDIT right on the job; other roles require SHOW. Guests must also match the project client and have the right to view other users' projects. # Get plain conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/get-plain-conversation /openapi/phrase-tms-latest.json get /api2/v1/jobs/{jobUid}/conversations/plains/{conversationId} Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # List all conversations Source: https://developers.phrase.com/en/api/tms/latest/conversations/list-all-conversations /openapi/phrase-tms-latest.json get /api2/v1/jobs/{jobUid}/conversations Returns conversations of all types for the given job. Available to internal, guest and linguist users. Project managers require the EDIT right on the job; other roles require SHOW. Guests must also match the project client and have the right to view other users' projects. # List LQA conversations Source: https://developers.phrase.com/en/api/tms/latest/conversations/list-lqa-conversations /openapi/phrase-tms-latest.json get /api2/v1/jobs/{jobUid}/conversations/lqas Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # List plain conversations Source: https://developers.phrase.com/en/api/tms/latest/conversations/list-plain-conversations /openapi/phrase-tms-latest.json get /api2/v1/jobs/{jobUid}/conversations/plains Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Search conversation by project Source: https://developers.phrase.com/en/api/tms/latest/conversations/search-conversation-by-project /openapi/phrase-tms-latest.json post /api2/v1/jobs/conversations/searchByProject This endpoint is allowed only to PM and ADMIN roles. # Handling API Rate Limits Source: https://developers.phrase.com/en/api/tms/latest/handling-api-rate-limits This guide explains how to implement **rate limit prevention and recovery** in a **fully reactive Java service**, using: * Spring Boot `@Scheduled` polling (for illustration only) * `WebClient` for non-blocking HTTP * Resilience4j `RateLimiter` for token-bucket control * Reactor `Mono` for reactive chaining ## Why avoid hitting rate limits? Rate-limited APIs (like [Phrase’s](https://support.phrase.com/hc/en-us/articles/5784117234972-Phrase-TMS-Limits)) reject requests when you exceed a quota — for logged in users at Phrase, **6000 requests per minute**. Hitting the limit can cause: * HTTP `429 Too Many Requests` responses * Retries that worsen load (retry storms) * Degradation of service or even temporary API bans (very rarely) **Best practice:** stay within the quota and handle overshoots *gracefully*. ## How to recover from hitting the limit Even with controls in place, you might overshoot occasionally. You should: * Detect `429` responses * Retry once with **jitter** (random delay) * Suppress stack traces for expected rate-limit errors * Never block threads ## Our Example This component polls the Phrase API periodically, respecting the rate limit and logging project names reactively. Retrieving a list of project names is really just an example that was used during the creation of this article to make sure the code works as intended. ### ⚙️ WebClient + Resilience4j Setup ```java theme={null} private final WebClient webClient; private final RateLimiter rateLimiter; public ScheduledPoller( @Value("${phrase.base-url:https://cloud.memsource.com/web/api2/v1/}") String baseUrl, @Value("${phrase.api-token}") String apiToken, @Value("${phrase.rate-limit.rpm:6000}") int requestsPerMinute, WebClient.Builder builder ) { this.webClient = builder .baseUrl(baseUrl) .defaultHeader("Authorization", "ApiToken " + apiToken) .defaultHeader("Accept", "application/json") .build(); RateLimiterConfig config = RateLimiterConfig.custom() .timeoutDuration(Duration.ofMillis(0)) // fail fast .limitRefreshPeriod(Duration.ofMinutes(1)) // 1-minute refill window .limitForPeriod(requestsPerMinute) // e.g. 6000 RPM .build(); rateLimiter = RateLimiter.of("apiLimiter", config); } ``` 🔍 **Key points:** * The limiter allows `requestsPerMinute` API calls per minute (configurable). * It fails *immediately* if the quota is exhausted (no queueing or waiting). * No new threads are created — everything stays **non-blocking**. ### The API call method ```java theme={null} public Mono> listProjects() { return webClient.get() .uri(u -> u.path("projects") .queryParam("pageSize", 50) .queryParam("pageNumber", 0) .queryParam("includeArchived", false) .build()) .retrieve() .bodyToMono(JsonNode.class) .transformDeferred(RateLimiterOperator.of(rateLimiter)) .map(this::extractProjectNames) .retryWhen( Retry.fixedDelay(1, Duration.ofSeconds(1)) // retry once .jitter(0.5) // 50% jitter .filter(ex -> ex instanceof WebClientResponseException.TooManyRequests) ); } ``` 🔍 **Highlights:** * Applies the **rate limiter reactively** using `transformDeferred(...)`. * Uses `retryWhen(...)` to retry only on `429` errors. * Adds **jitter** to avoid retry storms. ### JSON → Project name extraction ```java theme={null} private List extractProjectNames(JsonNode json) { return StreamSupport.stream(json.path("content").spliterator(), false) .map(p -> p.path("name").asText()) .collect(Collectors.toList()); } ``` 🔍 Cleanly extracts `"name"` from the `"content"` array in the JSON response. Just for readability. ### Polling logic with logging & error handling ```java theme={null} @Scheduled(fixedDelayString = "${phrase.poll.delay-ms:100}") public void poll() { listProjects() .subscribe( names -> log.info("Projects: {}", names), error -> { if (error instanceof RequestNotPermitted) { log.warn("Rate limit exceeded - are you too fast for Phrase?"); } else { log.error("Unexpected error during project poll", error); } } ); } ``` 🔍 **Explanation**: * The poller runs every 100 milliseconds by default (configurable via `phrase.poll.delay-ms`). While this is safely within the defined rate limit, it’s primarily for demonstration. Real-world applications will typically trigger API requests based on actual events, workflows, or user actions—not by polling a static endpoint in a tight loop. * Subscribes to the `Mono>` returned by `listProjects()`. * Handles: * `RequestNotPermitted` — **client-side** rate limit exceeded (token bucket empty) * Other exceptions (e.g. HTTP errors) ## What happens when the limit is hit? There are two possible failure scenarios: ### 1. Client-side limit exceeded * The `RateLimiter` detects that no tokens are left. * It **immediately fails** with `RequestNotPermitted`. * The `subscribe()` block catches it and logs: ```java theme={null} Rate limit exceeded - are you too fast for Phrase? ``` ✔️ No thread is blocked ✔️ No request is sent ✔️ No stack trace is thrown ### 2. Server returns HTTP 429 * The server says “too many requests” via a `429 Too Many Requests` response. * The `.retryWhen(...)` block triggers a **single retry** after a jittered delay. * If it fails again, the error is logged as usual. ## Summary | Concern | This Example Handles It With | | :------------------------ | :------------------------------------------ | | Avoiding rate limit | `RateLimiterOperator` with RPM config | | Failing fast on quota hit | `.timeoutDuration(Duration.ofMillis(0))` | | Retrying 429s | `.retryWhen(...).jitter(...).filter(...)` | | Logging gracefully | \`subscribe(..., error -> log.warn | | Staying non-blocking | Fully reactive: WebClient + Mono + Operator | ### Final Result A minimal but robust setup for: * Scheduled polling * Reactive rate limiting * Retry and error handling * Clean logs and no blocking You can drop this class into any Spring Boot app that uses `WebClient`, and you're good to go. # Handling Concurrent API Rate Limits Source: https://developers.phrase.com/en/api/tms/latest/handling-concurrent-api-limits Phrase’s API enforces not only **per-minute quotas** but also **concurrent request caps**. You can stay under your 6000 RPM limit and still hit `HTTP 429 Too Many Requests` if too many requests run in parallel. In this article, we’ll extend our previous rate-limiting example with **Bulkheads** and **two retry strategies**: * A **short exponential backoff** for global quota overshoots and transient failures. * A **long 1-minute backoff** for concurrency overshoots when Phrase signals via headers. ## Why Bulkheads? Without concurrency control, bursts of parallel requests can: * Trigger 429s even if the RPM (requests per minute) budget isn’t exhausted. * Cause retry storms if every client retries in lockstep. * Waste resources since failed concurrent requests still consume capacity. A **Bulkhead** protects your service by limiting simultaneous in-flight calls. Combined with a `RateLimiter`, it ensures you respect both Phrase’s RPM and concurrent caps. ## Setup: RateLimiter + Bulkhead We configure both quota- and concurrency-based protection: ```java theme={null} // Per-minute rate limiter RateLimiterConfig rlConfig = RateLimiterConfig.custom() .timeoutDuration(Duration.ZERO) .limitRefreshPeriod(Duration.ofMinutes(1)) .limitForPeriod(requestsPerMinute) .build(); this.rateLimiter = RateLimiter.of("apiLimiter", rlConfig); // Bulkhead for concurrent calls BulkheadConfig bhConfig = BulkheadConfig.custom() .maxConcurrentCalls(concurrentRequests) // e.g. 50 .maxWaitDuration(Duration.ZERO) // fail fast .build(); this.bulkhead = Bulkhead.of("apiBulkhead", bhConfig); ``` * **RateLimiter**: caps requests per minute. * **Bulkhead**: enforces max parallel requests (configurable via Spring - the example assumes you have a variable for that). ## Retry strategies We define two `RetryConfig`s with different backoff functions: ```java theme={null} // Global quota or transient errors: exponential backoff with jitter IntervalFunction globalBackoff = IntervalFunction.ofExponentialRandomBackoff( 1000, // base 1s 2.0, // multiplier 0.5 // ±50% jitter ); RetryConfig globalRetryConfig = RetryConfig.custom() .maxAttempts(5) .intervalFunction(globalBackoff) .retryOnException(ex -> ex instanceof WebClientResponseException.TooManyRequests || ex instanceof WebClientResponseException.ServiceUnavailable) .build(); this.globalRetry = Retry.of("globalRetry", globalRetryConfig); // Concurrency overshoot: long 1 min backoff with jitter IntervalFunction concurrentBackoff = IntervalFunction.ofRandomized( Duration.ofMinutes(1).toMillis(), 0.1); // ±10% RetryConfig concurrentRetryConfig = RetryConfig.custom() .maxAttempts(3) .intervalFunction(concurrentBackoff) .retryOnException(ex -> ex instanceof WebClientResponseException.TooManyRequests) .build(); this.concurrentRetry = Retry.of("concurrentRetry", concurrentRetryConfig); ``` * **Global retry**: exponential backoff, short delays, jittered to avoid retry storms. * **Concurrent retry**: fixed 1-minute delay with jitter, conservative and respectful. ## The API call ```java theme={null} public Mono> listProjects() { // this is just calling the API Supplier>> call = () -> webClient.get() .uri(uriBuilder -> uriBuilder .path("projects") .queryParam("pageSize", 50) .queryParam("pageNumber", 0) .queryParam("includeArchived", false) .build()) .retrieve() .bodyToMono(JsonNode.class) .map(this::extractProjectNames); // here the prevention & recovery are put together return Mono.defer(call) .transformDeferred(BulkheadOperator.of(bulkhead)) .transformDeferred(RateLimiterOperator.of(rateLimiter)) .onErrorResume(WebClientResponseException.TooManyRequests.class, ex -> { HttpHeaders headers = ex.getHeaders(); if (headers != null && headers.containsKey("Ratelimit-Limit") && headers.containsKey("Ratelimit-Remaining")) { // concurrent limit → long backoff return Mono.defer(call) .transformDeferred(RetryOperator.of(concurrentRetry)); } else { // global limit → shorter backoff return Mono.defer(call) .transformDeferred(RetryOperator.of(globalRetry)); } }); } ``` * Both `BulkheadOperator` and `RateLimiterOperator` decorate the call. * On `429 Too Many Requests`, the presence or absence of specific headers tells you which type of limit has been hit. This behavior is particular to **Phrase TMS**: * If the response **includes** `Ratelimit-Limit` **and** `Ratelimit-Remaining` **headers**, it means the **concurrent request limit** was exceeded. * If those headers are **absent**, the failure was caused by the **global per-minute quota**. The distinction comes from how Phrase enforces limits internally: * **Global limits** are applied at the proxy layer, so no application specific headers are there. * **Concurrent limits** are enforced within the application itself, and that’s why the extra headers are present when they trigger. ## Polling with logging ```java theme={null} @Scheduled(fixedDelayString = "${phrase.poll.delay-ms:200}") public void poll() { listProjects() .subscribe( names -> log.info("Projects: {}", names), error -> { if (error instanceof RequestNotPermitted) { log.warn("Rate limiter triggered: too many requests per minute"); } else if (error instanceof BulkheadFullException) { log.warn("Bulkhead full: too many concurrent requests"); } else { log.error("Unexpected error during project poll", error); } } ); } ``` This makes it clear in logs whether: * The **RateLimiter** was tripped, * The **Bulkhead** was full, or * Some other error occurred. ## Summary | Concern | Solution | | :-------------------------- | :------------------------------------------- | | Avoiding per-minute quota | `RateLimiter` | | Avoiding concurrency bursts | `Bulkhead` | | Global overshoot / 5xx | `globalRetry` (exponential + jitter) | | Concurrency overshoot | `concurrentRetry` (1m + jitter) | | Logging & observability | Explicit branches in `poll()` error handling | | Non-blocking design | Reactive `Mono`, no threads are blocked | ## Final Result With this setup you get a **fully reactive, header-aware, concurrency-safe client**: * **Bulkhead** prevents overload before requests leave your service. * **RateLimiter** enforces RPM quotas. * **Two retry configs** ensure retries are smart, respectful, and jittered. * **Logs** clearly differentiate what kind of limit was exceeded. # Introduction Source: https://developers.phrase.com/en/api/tms/latest/introduction ## Phrase TMS API Reference () Welcome to Phrase's TMS API documentation. Please visit our [help center](https://support.phrase.com/hc/en-us/sections/5709662083612) for more information about the APIs. If you have any questions, please contact [Support](https://support.phrase.com/hc/requests/new). Please, include the `User-Agent` header with the name of your application or project. It might be a good idea to include some sort of contact information as well, so that we can get in touch if necessary. Examples of excellent `User-Agent` headers: ``` User-Agent: Example mobile app (example@phrase.com) User-Agent: ACME Inc Java 1.8 Client (http://acmeinc.com/contact) ``` # Add LQA comment Source: https://developers.phrase.com/en/api/tms/latest/conversations/add-lqa-comment /openapi/phrase-tms-latest.json post /api2/v2/jobs/{jobUid}/conversations/lqas/{conversationId}/comments Returns a result wrapper containing the new comment id and the updated conversation. Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Add plain comment Source: https://developers.phrase.com/en/api/tms/latest/conversations/add-plain-comment /openapi/phrase-tms-latest.json post /api2/v3/jobs/{jobUid}/conversations/plains/{conversationId}/comments To notify a user or group, the comment text must contain a mention tag in the exact wire format <@user:UID> or <@group:GROUPNAME> (e.g. <@group:owners>) — see AddCommentDto.text. Only identifiers returned by the "List mentionable users" endpoint for this job part are valid mention targets. Plain human-readable text such as "@owners" is not recognized as a mention; it is stored as inert text and no notification is sent. # Create LQA conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/create-lqa-conversation /openapi/phrase-tms-latest.json post /api2/v2/jobs/{jobUid}/conversations/lqas Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Create plain conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/create-plain-conversation /openapi/phrase-tms-latest.json post /api2/v3/jobs/{jobUid}/conversations/plains # Edit LQA comment Source: https://developers.phrase.com/en/api/tms/latest/conversations/edit-lqa-comment /openapi/phrase-tms-latest.json put /api2/v2/jobs/{jobUid}/conversations/lqas/{conversationId}/comments/{commentId} Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Edit plain comment Source: https://developers.phrase.com/en/api/tms/latest/conversations/edit-plain-comment /openapi/phrase-tms-latest.json put /api2/v3/jobs/{jobUid}/conversations/plains/{conversationId}/comments/{commentId} # Update LQA conversation Source: https://developers.phrase.com/en/api/tms/latest/conversations/update-lqa-conversation /openapi/phrase-tms-latest.json put /api2/v2/jobs/{jobUid}/conversations/lqas/{conversationId} Available to internal, guest and linguist users; project managers require the EDIT right on the job, other roles require SHOW, and guests must also match the project client and have the right to view other users' projects. # Create cost center Source: https://developers.phrase.com/en/api/tms/latest/cost-center/create-cost-center /openapi/phrase-tms-latest.json post /api2/v1/costCenters Requires ADMIN or PROJECT_MANAGER role with the "Setup server" access right. The `name` field is mandatory. # Delete cost center Source: https://developers.phrase.com/en/api/tms/latest/cost-center/delete-cost-center /openapi/phrase-tms-latest.json delete /api2/v1/costCenters/{costCenterUid} Soft-deletes the cost center and removes its association from any Project, ProjectTemplate, ProjectFilter, and ProjectTemplateFilter. Requires ADMIN or PROJECT_MANAGER role with the "Setup server" access right. # Edit cost center Source: https://developers.phrase.com/en/api/tms/latest/cost-center/edit-cost-center /openapi/phrase-tms-latest.json put /api2/v1/costCenters/{costCenterUid} Only non-null fields in the request body are applied (partial update). Requires ADMIN or PROJECT_MANAGER role with the "Setup server" access right. # Get cost center Source: https://developers.phrase.com/en/api/tms/latest/cost-center/get-cost-center /openapi/phrase-tms-latest.json get /api2/v1/costCenters/{costCenterUid} # List of cost centers Source: https://developers.phrase.com/en/api/tms/latest/cost-center/list-of-cost-centers /openapi/phrase-tms-latest.json get /api2/v1/costCenters Accessible only by users with the ADMIN or PROJECT_MANAGER role. Results are scoped to the caller's organization. The `name` filter uses prefix matching. # Create custom field Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/create-custom-field /openapi/phrase-tms-latest.json post /api2/v1/customFields Creates a new custom field for the organization. The `type` controls how options are handled: only `SINGLE_SELECT` and `MULTI_SELECT` fields use predefined options supplied via `options`; for all other types `options` is ignored. When `required` is `true`, the field must be filled in for the entities listed in `allowedEntities`. # Create TB custom field Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/create-tb-custom-field /openapi/phrase-tms-latest.json post /api2/v1/termBases/customFields # Delete custom field Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/delete-custom-field /openapi/phrase-tms-latest.json delete /api2/v1/customFields/{fieldUid} # Delete TB custom field Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/delete-tb-custom-field /openapi/phrase-tms-latest.json delete /api2/v1/termBases/customFields/{id} # Deprecate custom field option Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/deprecate-custom-field-option /openapi/phrase-tms-latest.json put /api2/v1/customFields/{fieldUid}/options/{optionUid}/deprecate Deprecates or reactivates a single option of a `SINGLE_SELECT` or `MULTI_SELECT` custom field. Set `deprecated` to `true` to deprecate the option or to `false` to reactivate it. # Edit custom field Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/edit-custom-field /openapi/phrase-tms-latest.json put /api2/v1/customFields/{fieldUid} Updates an existing custom field. The custom field `type` cannot be changed and is therefore not part of the request body. For `SINGLE_SELECT` and `MULTI_SELECT` fields, options are managed through dedicated lists in the request body: `addOptions` adds new options by value, `removeOptions` removes existing options by UID, `deprecateOptions` marks existing options as deprecated by UID, and `undeprecateOptions` reverts deprecated options by UID. # Edit TB custom field Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/edit-tb-custom-field /openapi/phrase-tms-latest.json patch /api2/v1/termBases/customFields/{id} # Get custom field Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/get-custom-field /openapi/phrase-tms-latest.json get /api2/v1/customFields/{fieldUid} # List TB custom fields Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/list-tb-custom-fields /openapi/phrase-tms-latest.json get /api2/v1/termBases/customFields # Lists custom fields Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/lists-custom-fields /openapi/phrase-tms-latest.json get /api2/v1/customFields Returns a paginated list of custom fields for the organization. For each custom field only a truncated set of options is returned (`options.truncatedOptions`, at most 5 items, with `options.remainingCount` indicating how many further options exist). To retrieve all options of a field, use the dedicated `GET /api2/v1/customFields/{fieldUid}/options` endpoint. # Lists options of custom field Source: https://developers.phrase.com/en/api/tms/latest/custom-fields/lists-options-of-custom-field /openapi/phrase-tms-latest.json get /api2/v1/customFields/{fieldUid}/options Returns a paginated list of all options of the given custom field. Only `SINGLE_SELECT` and `MULTI_SELECT` custom fields have options; for other field types the list is empty. # Create custom file type Source: https://developers.phrase.com/en/api/tms/latest/custom-file-type/create-custom-file-type /openapi/phrase-tms-latest.json post /api2/v1/customFileTypes The `type` field accepts only the following values: html, json, xml, multiling_xml, txt. The response `supportsContinuousJob` flag is derived from the file type. Returns 501 Not Implemented when custom file types are not enabled for the organization. # Delete custom file type Source: https://developers.phrase.com/en/api/tms/latest/custom-file-type/delete-custom-file-type /openapi/phrase-tms-latest.json delete /api2/v1/customFileTypes/{customFileTypeUid} Returns 501 Not Implemented when custom file types are not enabled for the organization. # Delete multiple custom file types Source: https://developers.phrase.com/en/api/tms/latest/custom-file-type/delete-multiple-custom-file-types /openapi/phrase-tms-latest.json delete /api2/v1/customFileTypes Returns 501 Not Implemented when custom file types are not enabled for the organization. # Find custom file type Source: https://developers.phrase.com/en/api/tms/latest/custom-file-type/find-custom-file-type /openapi/phrase-tms-latest.json get /api2/v1/customFileTypes/find Finds the custom file type whose filename pattern matches the given `fileName`. If no matching custom file type is found it returns status 200 and an empty body. The response `supportsContinuousJob` flag is derived from the file type. Returns 501 Not Implemented when custom file types are not enabled for the organization. # Get all custom file types Source: https://developers.phrase.com/en/api/tms/latest/custom-file-type/get-all-custom-file-types /openapi/phrase-tms-latest.json get /api2/v1/customFileTypes The `supportsContinuousJob` flag of each item is derived from the file type. Returns 501 Not Implemented when custom file types are not enabled for the organization. # Get custom file type Source: https://developers.phrase.com/en/api/tms/latest/custom-file-type/get-custom-file-type /openapi/phrase-tms-latest.json get /api2/v1/customFileTypes/{customFileTypeUid} The response `supportsContinuousJob` flag is derived from the file type. Returns 501 Not Implemented when custom file types are not enabled for the organization. # Update custom file type Source: https://developers.phrase.com/en/api/tms/latest/custom-file-type/update-custom-file-type /openapi/phrase-tms-latest.json put /api2/v1/customFileTypes/{customFileTypeUid} The `type` field accepts only the following values: html, json, xml, multiling_xml, txt. The response `supportsContinuousJob` flag is derived from the file type. Returns 501 Not Implemented when custom file types are not enabled for the organization. # Create domain Source: https://developers.phrase.com/en/api/tms/latest/domain/create-domain /openapi/phrase-tms-latest.json post /api2/v1/domains Domain name must be unique within the organisation. # Delete domain Source: https://developers.phrase.com/en/api/tms/latest/domain/delete-domain /openapi/phrase-tms-latest.json delete /api2/v1/domains/{domainUid} Deletes the domain and removes its reference from all projects, project templates, translation memories, and term bases. Also removes all user and vendor domain assignments. Project managers who did not create the domain need the clientDeleteOther access right (default off) to delete it. # Edit domain Source: https://developers.phrase.com/en/api/tms/latest/domain/edit-domain /openapi/phrase-tms-latest.json put /api2/v1/domains/{domainUid} Name must be unique within the organisation if provided. Pass null to leave it unchanged. Project managers who did not create the domain need the clientEditOther access right (default off) to edit it. # Get domain Source: https://developers.phrase.com/en/api/tms/latest/domain/get-domain /openapi/phrase-tms-latest.json get /api2/v1/domains/{domainUid} Project managers who did not create the domain need the clientViewOther access right (default off) to view it. # List of domains Source: https://developers.phrase.com/en/api/tms/latest/domain/list-of-domains /openapi/phrase-tms-latest.json get /api2/v1/domains Returns domains belonging to the caller's organisation. Domain is the org-configurable field used to tag/categorize content type (e.g. Marketing, Legal, Medical, Technical) on projects, project templates, translation memories, and term bases. Results are role-dependent: LINGUIST, SUBMITTER, and GUEST roles receive only domains associated with projects they are assigned to. Other roles receive all organisation domains, further restricted by the caller's clientViewOther access right (if false, only domains created by the caller are returned). For LINGUIST, SUBMITTER, and GUEST roles, pageNumber is ignored and page 0 is always returned. # Create due date scheme Source: https://developers.phrase.com/en/api/tms/latest/due-date-scheme/create-due-date-scheme /openapi/phrase-tms-latest.json post /api2/v1/dueDateSchemes # Delete due date schemes (batch) Source: https://developers.phrase.com/en/api/tms/latest/due-date-scheme/delete-due-date-schemes-batch /openapi/phrase-tms-latest.json delete /api2/v1/dueDateSchemes # Edit due date scheme Source: https://developers.phrase.com/en/api/tms/latest/due-date-scheme/edit-due-date-scheme /openapi/phrase-tms-latest.json put /api2/v1/dueDateSchemes/{dueDateSchemeUid} Replaces the whole due date scheme - fields left out are reset to their default value. # Get due date scheme Source: https://developers.phrase.com/en/api/tms/latest/due-date-scheme/get-due-date-scheme /openapi/phrase-tms-latest.json get /api2/v1/dueDateSchemes/{dueDateSchemeUid} # List due date schemes Source: https://developers.phrase.com/en/api/tms/latest/due-date-scheme/list-due-date-schemes /openapi/phrase-tms-latest.json get /api2/v1/dueDateSchemes # Create (or duplicate/clone) email template Source: https://developers.phrase.com/en/api/tms/latest/email-template/create-or-duplicateclone-email-template /openapi/phrase-tms-latest.json post /api2/v1/emailTemplates Requires an internal user role (Admin or Project Manager) with the Setup server access right. Also used to duplicate/clone an existing template: fetch the source template via list/get, then resubmit its fields here (typically with a new name). # Delete email template Source: https://developers.phrase.com/en/api/tms/latest/email-template/delete-email-template /openapi/phrase-tms-latest.json delete /api2/v1/emailTemplates/{templateUid} Requires an internal user role (Admin or Project Manager) with the Setup server access right. Deletion fails with 400 Bad Request if the template is currently assigned to an active job widget. On deletion, the template reference is cleared from all associated job widgets, project template workflow settings, automated project configurations, and job parts. # Get email template Source: https://developers.phrase.com/en/api/tms/latest/email-template/get-email-template /openapi/phrase-tms-latest.json get /api2/v1/emailTemplates/{templateUid} Requires an internal user role (Admin or Project Manager). To duplicate/clone this template under a new name, submit its returned fields to the create-email-template endpoint. # Get email template types Source: https://developers.phrase.com/en/api/tms/latest/email-template/get-email-template-types /openapi/phrase-tms-latest.json get /api2/v1/emailTemplates/types Requires an internal user role (Admin or Project Manager). Returns the allowed values for the type field/filter used by the other email template endpoints. # List email templates Source: https://developers.phrase.com/en/api/tms/latest/email-template/list-email-templates /openapi/phrase-tms-latest.json get /api2/v1/emailTemplates Requires an internal user role (Admin or Project Manager). To duplicate/clone an existing template, look up its fields here or via the get-single-template endpoint, then submit them (with a new name) to the create-email-template endpoint. # Send test email Source: https://developers.phrase.com/en/api/tms/latest/email-template/send-test-email /openapi/phrase-tms-latest.json post /api2/v1/emailTemplates/testSend Sends a test email with the given subject and body to the currently authenticated user, to preview formatting/macros before creating or updating a stored template. Available to any authenticated user (including BOT/service-account users); no specific role is required. Does not reference an existing template by UID — pass the subject/body to preview directly. # Update email template Source: https://developers.phrase.com/en/api/tms/latest/email-template/update-email-template /openapi/phrase-tms-latest.json put /api2/v1/emailTemplates/{templateUid} Requires an internal user role (Admin or Project Manager) with the Setup server access right. Replaces all editable fields of the template; it is a full update, not a partial patch — omitted optional fields (ccAddress/bccAddress) are cleared. # Delete file Source: https://developers.phrase.com/en/api/tms/latest/file/delete-file /openapi/phrase-tms-latest.json delete /api2/v1/files/{fileUid} # Get file Source: https://developers.phrase.com/en/api/tms/latest/file/get-file /openapi/phrase-tms-latest.json get /api2/v1/files/{fileUid} Get uploaded file as octet-stream or as json based on 'Accept' header # List files Source: https://developers.phrase.com/en/api/tms/latest/file/list-files /openapi/phrase-tms-latest.json get /api2/v1/files # Upload file Source: https://developers.phrase.com/en/api/tms/latest/file/upload-file /openapi/phrase-tms-latest.json post /api2/v1/files Accepts multipart/form-data, application/octet-stream or application/json. # Activate/Deactivate glossary Source: https://developers.phrase.com/en/api/tms/latest/glossary/activatedeactivate-glossary /openapi/phrase-tms-latest.json put /api2/v1/glossaries/{glossaryUid}/activate Activates the glossary when active is true and deactivates it when active is false. # Create glossary Source: https://developers.phrase.com/en/api/tms/latest/glossary/create-glossary /openapi/phrase-tms-latest.json post /api2/v1/glossaries Available to internal users only (Admin or Project Manager). # Delete glossary Source: https://developers.phrase.com/en/api/tms/latest/glossary/delete-glossary /openapi/phrase-tms-latest.json delete /api2/v1/glossaries/{glossaryUid} When purge is false the glossary is soft-deleted and can later be restored. When purge is true the glossary is permanently deleted and cannot be restored. # Edit glossary Source: https://developers.phrase.com/en/api/tms/latest/glossary/edit-glossary /openapi/phrase-tms-latest.json put /api2/v1/glossaries/{glossaryUid} Languages can only be added, their removal is not supported. The glossary owner must be an Admin or Project Manager. # Export glossary Source: https://developers.phrase.com/en/api/tms/latest/glossary/export-glossary /openapi/phrase-tms-latest.json get /api2/v1/glossaries/{glossaryUid}/export This API endpoint is still limited access, and only available to customers on the Enterprise plans on request. Please contact support or your customer success manager if you are interested. # Get glossary Source: https://developers.phrase.com/en/api/tms/latest/glossary/get-glossary /openapi/phrase-tms-latest.json get /api2/v1/glossaries/{glossaryUid} # List glossaries Source: https://developers.phrase.com/en/api/tms/latest/glossary/list-glossaries /openapi/phrase-tms-latest.json get /api2/v1/glossaries # Purge glossary Source: https://developers.phrase.com/en/api/tms/latest/glossary/purge-glossary /openapi/phrase-tms-latest.json post /api2/v1/glossaries/{glossaryUid}/purge This API endpoint is still limited access, and only available to customers on the Enterprise plans on request. Please contact support or your customer success manager if you are interested. # Upload glossary Source: https://developers.phrase.com/en/api/tms/latest/glossary/upload-glossary /openapi/phrase-tms-latest.json post /api2/v1/glossaries/{glossaryUid}/upload This API endpoint is still limited access, and only available to customers on the Enterprise plans on request. Please contact support or your customer success manager if you are interested. Glossaries can be imported from XLS/XLSX and TBX file formats. # Create import settings Source: https://developers.phrase.com/en/api/tms/latest/import-settings/create-import-settings /openapi/phrase-tms-latest.json post /api2/v1/importSettings Pre-defined import settings is handy for [Create Job](../job/create-job). See [supported file types](https://wiki.memsource.com/wiki/API_File_Type_List) Requires an internal role (Admin or Project Manager) with the server setup right. # Delete import settings Source: https://developers.phrase.com/en/api/tms/latest/import-settings/delete-import-settings /openapi/phrase-tms-latest.json delete /api2/v1/importSettings/{uid} # Edit import settings Source: https://developers.phrase.com/en/api/tms/latest/import-settings/edit-import-settings /openapi/phrase-tms-latest.json put /api2/v1/importSettings The import settings to update are resolved by the uid in the request body. Requires an internal role (Admin or Project Manager) with the access-settings right to set up the server. # Edit organization's default import settings Source: https://developers.phrase.com/en/api/tms/latest/import-settings/edit-organizations-default-import-settings /openapi/phrase-tms-latest.json put /api2/v1/importSettings/default Updates the import settings configured as the default for the organization. Requires an internal role (Admin or Project Manager) with the access-settings right to set up the server. # Get import settings Source: https://developers.phrase.com/en/api/tms/latest/import-settings/get-import-settings /openapi/phrase-tms-latest.json get /api2/v1/importSettings/{uid} # Get organization's default import settings Source: https://developers.phrase.com/en/api/tms/latest/import-settings/get-organizations-default-import-settings /openapi/phrase-tms-latest.json get /api2/v1/importSettings/default Returns the import settings configured as the default for the organization. # List import settings Source: https://developers.phrase.com/en/api/tms/latest/import-settings/list-import-settings /openapi/phrase-tms-latest.json get /api2/v1/importSettings Accessible to internal roles (Admin, Project Manager); other roles receive 403. # Clone jobs Source: https://developers.phrase.com/en/api/tms/latest/job/clone-jobs /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/clone Clones the selected jobs into new target languages, optionally applying per-workflow-step settings: linguist/vendor assignment per target language, due date and notify-linguist (email template + reminder interval) per workflow step. The project must have more than one target language and must not have reached its job limit; multilingual jobs are rejected. # Compare jobs on workflow levels Source: https://developers.phrase.com/en/api/tms/latest/job/compare-jobs-on-workflow-levels /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/compare # Copy Source to Target Source: https://developers.phrase.com/en/api/tms/latest/job/copy-source-to-target /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/copySourceToTarget # Copy Source to Target job Source: https://developers.phrase.com/en/api/tms/latest/job/copy-source-to-target-job /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/copySourceToTarget # Create custom field instances Source: https://developers.phrase.com/en/api/tms/latest/job/create-custom-field-instances /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobPartUid}/customFields # Create job Source: https://developers.phrase.com/en/api/tms/latest/job/create-job /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs Upload a source file to create a translation job in the specified project. An API call to create a [job](https://support.phrase.com/hc/en-us/articles/5709686763420-Jobs-TMS-) within a specified [project](https://support.phrase.com/hc/en-us/articles/5709748435484-Projects-TMS-). The source file can be uploaded directly in the message body or downloaded from connector. **Job import is asynchronous.** The file is processed in the background after this call returns. The response body includes an `asyncRequest` object; poll [Get asynchronous request](../async-request/get-asynchronous-request) (action: `IMPORT_JOB`) to track import progress. To check whether individual jobs are ready, poll [Get job](../job/get-job) and inspect the `importStatus.status` field (`RUNNING`, `ERROR`, `OK`). Please supply job metadata in `Memsource` header. For file in the request body provide also the filename in `Content-Disposition` header. Accepted metadata: - **targetLangs** - This parameter specifies what languages should the job be created in. Only languages that are present in the project are supported, but this parameter accepts a subset of languages. When the file is uploaded, the number of jobs created (and returned) corresponds to the number of target languages and the workflow steps of the project. For example, `sample.json` imported for `EN>DE` and `EN>FR` language combination into a project with `Translation` and `Review` workflow steps will result in 4 jobs being created, one for each language and step. _Note_: Each time a file is uploaded, the resulting wordcount for each target language (not workflow step) is counted towards the organization's allowance. - **due** - ISO 8601 - **workflowSettings** - This parameter is used to set up assignments and due date for projects with workflow steps. When a project is created, the global workflow steps available via [List workflow steps](../workflow-step/list-workflow-steps) are instantiated for the given project at hand. To assign users or due dates, these project specific IDs need to be used instead of the global ones. - **assignments** - If a project does not contain workflow steps, this parameter can be used to assign users directly. - **importSettings** - Re-usable [import settings](../import-settings/create-import-settings) - **useProjectFileImportSettings** - When project is created, either global default setting or settings of a [project template](https://support.phrase.com/hc/en-us/articles/5709647439772-Project-Templates-TMS-) are copied into it. This parameter can be used to reference these project settings instead of using the API defaults. Mutually exclusive with importSettings - **callbackUrl** - A URL that can be notified when the job creation has been finished. Unlike [webhooks](https://support.phrase.com/hc/en-us/articles/5709693398812-Webhooks-TMS-) which are global for the entire account, the `callbackUrl` is set only for the specific operation at hand. - **path** - A parameter that can be used to specify a location of the source file and preserved for later download. This is automatically created when importing ZIP files. - **preTranslate** - When `true`, the system automatically starts [pre-translation](https://support.phrase.com/hc/en-us/articles/5709717749788-Pre-translation-TMS-) after import completes. Recommended when pre-translation is the goal: the platform handles the import-ready gate internally, removing the need to manually poll `importStatus.status`. - **semanticMarkup** - Set semantic markup processing after import when enabled for organization - **xmlAssistantProfile** - Apply XML import settings defined using XML assistant - **jobPreviewPackageFileUidRef** - reference to a job preview package file to create a preview for the imported file For remote file jobs also `remoteFile` can be added. To retrieve the information below, use the [connector](../connector/list-connectors) APIs. - **connectorToken** - Token of the connector for the purposes of the APIs - **remoteFolder** - An encoded name of the folder, retrieved by e.g. [List files in a subfolder](../connector/list-files-in-a-subfolder) - **remoteFileName** - An encoded name of the file, retrieved similarly to above. - **continuous** - Jobs created with files from a connector can be created as [continuous](https://support.phrase.com/hc/en-us/articles/5709711922972-Continuous-Jobs-CJ-TMS-) Create and assign job in project without workflow step: ``` { "targetLangs": [ "cs_cz" ], "callbackUrl": "https://my-shiny-service.com/consumeCallback", "importSettings": { "uid": "abcd123" }, "due": "2007-12-03T10:15:30.00Z", "path": "destination directory", "assignments": [ { "targetLang": "cs_cz", "providers": [ { "id": "4321", "type": "USER" } ] } ], "notifyProvider": { "organizationEmailTemplate": { "id": "39" }, "notificationIntervalInMinutes": "10" } } ``` Create job from remote file without workflow steps: ``` { "remoteFile": { "connectorToken": "948123ef-e1ef-4cd3-a90e-af1617848af3", "remoteFolder": "/", "remoteFileName": "Few words.docx", "continuous": false }, "assignments": [], "workflowSettings": [], "targetLangs": [ "cs" ] } ``` Create and assign job in project with workflow step: ``` { "targetLangs": [ "de" ], "useProjectFileImportSettings": "true", "workflowSettings": [ { "id": "64", "due": "2007-12-03T10:15:30.00Z", "assignments": [ { "targetLang": "de", "providers": [ { "id": "3", "type": "VENDOR" } ] } ], "notifyProvider": { "organizationEmailTemplate": { "id": "39" }, "notificationIntervalInMinutes": "10" } } ] } ``` Create a job with job preview package reference: ``` { "targetLangs": [ "de" ], "jobPreviewPackageFileUidRef": {"uid": "jobPreviewPackageFileUid123"} } ``` # Create job from connector asynchronous download task Source: https://developers.phrase.com/en/api/tms/latest/job/create-job-from-connector-asynchronous-download-task /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/connectorTask Creates the job in project specified by path param projectUid. Source file is defined by downloadTaskId parameter. That is value of finished download async task [Connector - Download file (async)](../connector/download-file-async). Please supply job metadata in body. Accepted metadata: - `targetLangs` - **required** - `due` - ISO 8601 - `workflowSettings` - project with workflow - see examples bellow - `assignments` - project without workflows - see examples bellow - `importSettings` - re-usable import settings - see [Create import settings](../import-settings/create-import-settings) - `useProjectFileImportSettings` - mutually exclusive with importSettings - `callbackUrl` - consumer callback - `path` - original destination directory - `preTranslate` - set pre translate job after import - `semanticMarkup` - set semantic markup processing after import when enabled for organization - `xmlAssistantProfile` - apply XML import settings defined using XML assistant Create job simple (without workflow steps, without assignments): ``` { "targetLangs": [ "cs_cz", "es_es" ] } ``` Create and assign job in project without workflow step: ``` { "targetLangs": [ "cs_cz" ], "callbackUrl": "https://my-shiny-service.com/consumeCallback", "importSettings": { "uid": "abcd123" }, "due": "2007-12-03T10:15:30.00Z", "path": "destination directory", "assignments": [ { "targetLang": "cs_cz", "providers": [ { "id": "4321", "type": "USER" } ] } ], "notifyProvider": { "organizationEmailTemplate": { "id": "39" }, "notificationIntervalInMinutes": "10" } } ``` Create and assign job in project with workflow step: ``` { "targetLangs": [ "de" ], "useProjectFileImportSettings": "true", "workflowSettings": [ { "id": "64", "due": "2007-12-03T10:15:30.00Z", "assignments": [ { "targetLang": "de", "providers": [ { "id": "3", "type": "VENDOR" } ] } ], "notifyProvider": { "organizationEmailTemplate": { "id": "39" }, "notificationIntervalInMinutes": "10" } } ] } ``` # Delete all translations Source: https://developers.phrase.com/en/api/tms/latest/job/delete-all-translations /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/jobs/translations # Delete custom field Source: https://developers.phrase.com/en/api/tms/latest/job/delete-custom-field /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/jobs/{jobPartUid}/customFields/{instanceUid} # Delete handover file Source: https://developers.phrase.com/en/api/tms/latest/job/delete-handover-file /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/fileHandovers # Delete job (batch) Source: https://developers.phrase.com/en/api/tms/latest/job/delete-job-batch /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/jobs/batch # Download bilingual file (also used to bulk-edit translations, confirm, or lock/unlock segments via re-import) Source: https://developers.phrase.com/en/api/tms/latest/job/download-bilingual-file-also-used-to-bulk-edit-translations-confirm-or-lockunlock-segments-via-re-import /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/bilingualFile This API call generates a bilingual file in the chosen format by merging all submitted jobs together. Note that all submitted jobs must belong to the same project; it's not feasible to merge jobs from multiple projects. When dealing with MXLIFF or DOCX files, modifications made externally can be imported back into the Phrase TMS project. Any changes will be synchronized into the editor, allowing actions like confirming or locking segments. Unlike the user interface (UI), the APIs also support XLIFF as a bilingual format. While MXLIFF files are editable using various means, their primary intended use is with the [CAT Desktop Editor](https://support.phrase.com/hc/en-us/articles/5709683873052-CAT-Desktop-Editor-TMS-). It's crucial to note that alterations to the file incompatible with the CAT Desktop Editor's features may result in a corrupted file, leading to potential loss or duplication of work. # Download handover file(s) Source: https://developers.phrase.com/en/api/tms/latest/job/download-handover-files /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/fileHandovers For downloading multiple files as ZIP file provide multiple IDs in query parameters. * For example `?jobUid={id1}&jobUid={id2}` * When no files matched given IDs error 404 is returned, otherwise ZIP file will include those that were found # Download original file Source: https://developers.phrase.com/en/api/tms/latest/job/download-original-file /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid}/original The response Content-Type is always application/octet-stream regardless of the original file format. The filename in Content-Disposition preserves the original name and may have no extension if the job was imported without one. # Edit custom field Source: https://developers.phrase.com/en/api/tms/latest/job/edit-custom-field /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/jobs/{jobPartUid}/customFields/{instanceUid} # Edit custom fields (batch) Source: https://developers.phrase.com/en/api/tms/latest/job/edit-custom-fields-batch /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/jobs/{jobPartUid}/customFields # Edit job (assign provider, due date, status) Source: https://developers.phrase.com/en/api/tms/latest/job/edit-job-assign-provider-due-date-status /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/jobs/{jobUid} This API call facilitates job editing using a PUT method. Unlike [Patch job](../job/patch-job), this call employs a PUT method, necessitating the inclusion of all parameters in the request. Omitting any parameter will reset its value to the default. For instance, if only the status field is included, the due date and provider fields will be emptied, even if they had previous values. It's recommended to either use a call like [Get job](../job/get-job) or [List jobs](../job/list-jobs) to gather the unchanged information or consider using the [Patch job](../job/patch-job) operation. This call supports editing the status, due date, and providers. When modifying providers, it's crucial to submit both the provider's ID and its type (either VENDOR or USER). To mark a job as completed (finished), set the status field to COMPLETED. Consider using [Edit job status](../job/edit-job-status) instead, since it does not require resending the due date and providers. Assigning a provider through this call does NOT send a notification email to the assigned provider. To notify providers of their assignment, call [Notify assigned users](../job/notify-assigned-users) with the emailTemplate.id of the template to send. The response will offer a subset of information from [Get job](../job/get-job). # Edit job import settings Source: https://developers.phrase.com/en/api/tms/latest/job/edit-job-import-settings /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/jobs/{jobUid}/importSettings Updates the job-level import settings for this already-imported job so that a subsequent reimport of the job's source file uses the new settings. This is distinct from the organization-level import settings templates managed via the import settings API (`/api2/v1/importSettings`). # Edit jobs (batch) Source: https://developers.phrase.com/en/api/tms/latest/job/edit-jobs-batch /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/jobs/batch Returns only jobs which were updated by the batch operation. # Extract candidate terms Source: https://developers.phrase.com/en/api/tms/latest/job/extract-candidate-terms /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/extractTerms Suggests candidate terms from the content of the given jobs, based on frequency and other heuristics. Returns an XLSX file listing the suggested terms. # Get custom field Source: https://developers.phrase.com/en/api/tms/latest/job/get-custom-field /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobPartUid}/customFields/{instanceUid} # Get custom fields Source: https://developers.phrase.com/en/api/tms/latest/job/get-custom-fields /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobPartUid}/customFields # Get import settings for job Source: https://developers.phrase.com/en/api/tms/latest/job/get-import-settings-for-job /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid}/importSettings Returns the job-level import settings currently applied to this already-imported job. This is distinct from the organization-level import settings templates managed via the import settings API (`/api2/v1/importSettings`). Use together with the edit job import settings endpoint to change these settings before a reimport of the job's source file. # Get job Source: https://developers.phrase.com/en/api/tms/latest/job/get-job /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid} This API call provides specific information about a [job](https://support.phrase.com/hc/en-us/articles/5709686763420-Jobs-TMS-) within a project. The response includes fundamental job details such as the current status, assigned providers, language combination, or [workflow step](https://support.phrase.com/hc/en-us/articles/5709717879324-Workflow-TMS-) to which the job belongs. Additionally, it offers a subset of the [Get project](../project/get-project) information. Furthermore, the response contains timestamps for the last [Update source and Update target](https://support.phrase.com/hc/en-us/articles/10825557848220-Job-Tools) operations executed on the job. If the job was imported as [continuous](https://support.phrase.com/hc/en-us/articles/5709711922972-Continuous-Jobs-CJ-TMS-), the job will be marked as such, and the response will include the timestamp of the last update. Moreover, the response features a boolean flag indicating if the job was imported successfully. It also highlights potential errors that might have occurred during the import process. The `jobReference` field serves as a unique identifier that allows matching corresponding jobs across different workflow steps. **Import readiness:** The `importStatus.status` field indicates whether file import has completed: - `RUNNING` — import is in progress - `ERROR` — import failed; check `importStatus.errorMessage` for details - `OK` — import succeeded; the job is ready for subsequent operations such as pre-translate Do not call [Pre-translate job](../job/pre-translate-job) until `importStatus.status` is `OK`. Calling it earlier returns `400 JOB_NOT_READY`. # Get Job Preview Package assets Source: https://developers.phrase.com/en/api/tms/latest/job/get-job-preview-package-assets /openapi/phrase-tms-latest.json get /api2/v1/jobs/{jobPartUid}/previewPackage/asset/{assetFileUid} URLs for this API are provided in html skeleton (preview) part of mxliff # Get segments count Source: https://developers.phrase.com/en/api/tms/latest/job/get-segments-count /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/segmentsCount This API provides the current count of segments (progress data). Every time this API is called, it returns the most up-to-date information. Consequently, these numbers will change dynamically over time. The data retrieved from this API call is utilized to calculate the progress percentage in the UI. The call returns the following information: Counts of characters, words, and segments for each of the locked, confirmed, and completed categories. In this context, _completed_ is defined as `confirmed` + `locked` - `confirmed and locked`. The number of added words if the [Update source](https://support.phrase.com/hc/en-us/articles/10825557848220-Job-Tools) operation has been performed on the job. In this context, added words are defined as the original word count plus the sum of words added during all subsequent update source operations. The count of segments where relevant machine translation (MT) was available (machineTranslationRelevantSegmentsCount) and the number of segments where the MT output was post-edited (machineTranslationPostEditedSegmentsCount). A breakdown of [Quality assurance](https://support.phrase.com/hc/en-us/articles/5709703799324-Quality-Assurance-QA-TMS-) results, including the number of segments on which it was performed, the count of warnings found, and the number of warnings that were ignored. Additionally, a breakdown of the aforementioned information from the previous [Workflow step](https://support.phrase.com/hc/en-us/articles/5709717879324-Workflow-TMS-) is also provided. # Notify assigned users Source: https://developers.phrase.com/en/api/tms/latest/job/notify-assigned-users /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/notifyAssigned # Patch job (assign provider, due date, status) Source: https://developers.phrase.com/en/api/tms/latest/job/patch-job-assign-provider-due-date-status /openapi/phrase-tms-latest.json patch /api2/v1/projects/{projectUid}/jobs/{jobUid} This API call allows for partial updates to jobs, modifying specific fields without overwriting those not included in the update request. Differing from [Edit job](../job/edit-job), this call employs a PATCH method, updating only the provided fields without altering others. It's beneficial when editing a subset of supported fields is required. The call supports the editing of status, due date, and providers. When editing providers, it's essential to submit both the ID of the provider and its type (either VENDOR or USER). The response will provide a subset of information from [Get job](../job/get-job). # Search jobs in project Source: https://developers.phrase.com/en/api/tms/latest/job/search-jobs-in-project /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/search This API call can be used to verify (search) which of the provided jobs belong to the specified project. For the jobs that belong to the project, a subset of [Get job](../job/get-job) information will be returned and the rest of the jobs will be filtered out. # Trigger quality evaluation for selected job parts Source: https://developers.phrase.com/en/api/tms/latest/job/trigger-quality-evaluation-for-selected-job-parts /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/evaluateQuality Runs quality evaluation asynchronously. Evaluation is based on the Content Group linked to the project — link one first via POST /api2/v1/projects/{projectUid}/contentGroup. Returns 422 Unprocessable Entity if the project has no Content Group linked. Job parts must belong to the same project, workflow step, and be in a ready state. Only unlocked segments are evaluated — already locked segments are skipped. Linguists may only evaluate job parts assigned to them. lockSegments defaults to true — segments that pass all AI checks are locked after evaluation. confirmSegments defaults to false — segments are not confirmed unless explicitly set to true. Returns an asyncRequest object. Poll GET /api2/v1/async/{asyncRequest.id} until asyncResponse is not null before retrieving results. Once the async job has completed, call POST /api2/v1/qualityProfiles/qeWarnings with the same job part UIDs to retrieve quality warnings. Alternatively, pass callbackUrl to be notified via a POST request once evaluation of all the selected job parts has finished, instead of polling. # Update source Source: https://developers.phrase.com/en/api/tms/latest/job/update-source /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/source Reimports an already-imported job by replacing its source file with a new one. This is a job-level operation, distinct from the organization-level import settings templates managed via the import settings API. API updated source file for specified job Job file can be provided directly in the message body. Please supply jobs in `Memsource` header. For file in the request body provide also the filename in `Content-Disposition` header. If a job from a multilingual file is updated, all jobs from the same file are update too even if their UIDs aren't listed in the jobs field. Accepted metadata: - `jobs` - **required** - list of jobs UID reference (maximum size `100`) - `preTranslate` - pre translate flag (default `false`) - `allowAutomaticPostAnalysis` - if automatic post editing analysis should be created. If not specified then value is taken from the analyse settings of the project - `callbackUrl` - consumer callback Job restrictions: - job must belong to project specified in path (`projectUid`) - job `UID` must be from the first workflow step - job cannot be split - job cannot be continuous - job cannot originate in a connector - status in any of the job's workflow steps cannot be a final status (`COMPLETED_BY_LINGUIST`, `COMPLETED`, `CANCELLED`) - job UIDs must be from the same multilingual file if a multilingual file is updated - multiple multilingual files or a mixture of multilingual and other jobs cannot be updated in one call File restrictions: - file cannot be a `.zip` file Example: ``` { "jobs": [ { "uid": "jobIn1stWfStepAndNonFinalStatusUid" } ], "preTranslate": false, "allowAutomaticPostAnalysis": false "callbackUrl": "https://my-shiny-service.com/consumeCallback" } ``` # Update target Source: https://developers.phrase.com/en/api/tms/latest/job/update-target /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/target API update target file for specified job Job file can be provided directly in the message body. Please supply jobs in `Memsource` header. For file in the request body provide also the filename in `Content-Disposition` header. Accepted metadata: - `jobs` - **required** - list of jobs UID reference (maximum size `1`) - `propagateConfirmedToTm` - sets if confirmed segments should be stored in TM (default value: true) - `callbackUrl` - consumer callback - `targetSegmentationRule` - ID reference to segmentation rule of organization to use for update target - `unconfirmChangedSegments` - sets if segments should stay unconfirmed Job restrictions: - job must belong to project specified in path (`projectUid`) - job cannot be split - job cannot be continuous - job cannot originate in a connector - job cannot have different file extension than original file File restrictions: - file cannot be a `.zip` file - update target is not allowed for jobs with file extensions: po, tbx, tmx, ttx, ts - update target for multilingual jobs works only with following file extensions: xliff, xlsx, csv Example: ``` { "jobs": [ { "uid": "jobUid" } ], "propagateConfirmedToTm": true, "targetSegmentationRule": { "id": "1" }, "callbackUrl": "https://my-shiny-service.com/consumeCallback" } ``` # Upload handover file Source: https://developers.phrase.com/en/api/tms/latest/job/upload-handover-file /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/fileHandovers For following jobs the handover file is not supported: * Continuous jobs * Jobs from connectors * Split jobs * Multilingual jobs # Delete specific translations Source: https://developers.phrase.com/en/api/tms/latest/job/delete-specific-translations /openapi/phrase-tms-latest.json delete /api2/v2/projects/{projectUid}/jobs/translations # Download preview file Source: https://developers.phrase.com/en/api/tms/latest/job/download-preview-file /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid}/preview # Download preview file Source: https://developers.phrase.com/en/api/tms/latest/job/download-preview-file-1 /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/preview Takes bilingual file (.mxliff only) as argument. If not passed, data will be taken from database # Download target file (async) Source: https://developers.phrase.com/en/api/tms/latest/job/download-target-file-async /openapi/phrase-tms-latest.json put /api2/v2/projects/{projectUid}/jobs/{jobUid}/targetFile This call initiates an asynchronous request to generate and download the target file containing translations. This request covers jobs created via actions like 'split jobs', ensuring accessibility even for such cases. To monitor the status of this asynchronous request, you have two options: 1. Use [Get asynchronous request](../async-request/get-asynchronous-request). 2. Search for the asyncRequestId by utilizing [List pending requests](../async-request/list-pending-requests). In contrast to the previous version (v1) of this call, v2 does not directly provide the target file within the response. Once the asynchronous request is completed, you can download the target file using [Download target file based on async request](../job/download-target-file-based-on-async-request). _Note_: The asyncRequestId can be used only once. Once the download is initiated through `Download target file based on async request`, the asyncRequestId becomes invalid for further use. _Note_: Issues with tags are a common cause of export failures (e.g. the file cannot be generated), especially for file types like spreadsheets (MS Excel based) and .XML. Before exporting, run quality assurance checks to ensure tags and formatting are correct. # Download target file (async) Source: https://developers.phrase.com/en/api/tms/latest/job/download-target-file-async-1 /openapi/phrase-tms-latest.json put /api2/v3/projects/{projectUid}/jobs/{jobUid}/targetFile This call initiates an asynchronous request to generate and download the target file containing translations. This request covers jobs created via actions like 'split jobs', ensuring accessibility even for such cases. To monitor the status of this asynchronous request, you have three options: 1. Use [Get asynchronous request](../async-request/get-asynchronous-request). 2. Search for the asyncRequestId by utilizing [List pending requests](../async-request/list-pending-requests). 3. Use callbackUrl to get notification that operation was finished In contrast to the previous version (v1) of this call, v2 does not directly provide the target file within the response. Once the asynchronous request is completed, you can download the target file using [Download target file based on async request](../job/download-target-file-based-on-async-request). _Note_: The asyncRequestId can be used only once. Once the download is initiated through `Download target file based on async request`, the asyncRequestId becomes invalid for further use. _Note_: Issues with tags are a common cause of export failures (e.g. the file cannot be generated), especially for file types like spreadsheets (MS Excel based) and .XML. Before exporting, run quality assurance checks to ensure tags and formatting are correct. # Download target file based on async request Source: https://developers.phrase.com/en/api/tms/latest/job/download-target-file-based-on-async-request /openapi/phrase-tms-latest.json get /api2/v2/projects/{projectUid}/jobs/{jobUid}/downloadTargetFile/{asyncRequestId} This call will return target file with translation. This means even for other jobs that were created via 'split jobs' etc. The asyncRequestId can be used only once. Once the download is initiated , the asyncRequestId becomes invalid for further use. # Edit job status Source: https://developers.phrase.com/en/api/tms/latest/job/edit-job-status /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/setStatus Changes the status of a single job. To mark a job as completed (finished), set the requestedStatus field to COMPLETED. # Edit jobs (with possible partial updates) Source: https://developers.phrase.com/en/api/tms/latest/job/edit-jobs-with-possible-partial-updates /openapi/phrase-tms-latest.json patch /api2/v3/jobs Bulk update up to 100 jobs across multiple projects in a single call. Supports setting dateDue (due date), status, providers, and custom fields. Use this endpoint to update due dates or reassign jobs in bulk without iterating project-by-project. Allows partial update, not breaking the whole batch if a single job fails. Per-job failures are collected in the response errors list with codes: AccessDenied, NotFound, JobImportFailed, JobCannotAssignProviders. Assigning providers through this call does NOT send a notification email to the assigned providers. To notify providers of their assignment, call [Notify assigned users](../job/notify-assigned-users) with the emailTemplate.id of the template to send. # Export jobs to online repository Source: https://developers.phrase.com/en/api/tms/latest/job/export-jobs-to-online-repository /openapi/phrase-tms-latest.json post /api2/v3/projects/{projectUid}/jobs/export # Get job's workflowStep Source: https://developers.phrase.com/en/api/tms/latest/job/get-jobs-workflowstep /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid}/workflowStep # Get segments Source: https://developers.phrase.com/en/api/tms/latest/job/get-segments /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid}/segments # Get status changes Source: https://developers.phrase.com/en/api/tms/latest/job/get-status-changes /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid}/statusChanges # Get status changes for jobs Source: https://developers.phrase.com/en/api/tms/latest/job/get-status-changes-for-jobs /openapi/phrase-tms-latest.json post /api2/v2/jobs/statusChanges # Get target file's warnings Source: https://developers.phrase.com/en/api/tms/latest/job/get-target-files-warnings /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid}/targetFileWarnings This call will return target file's warnings. This means even for other jobs that were created via 'split jobs' etc. # Get translation resources Source: https://developers.phrase.com/en/api/tms/latest/job/get-translation-resources /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/jobs/{jobUid}/translationResources # Get Web Editor URL Source: https://developers.phrase.com/en/api/tms/latest/job/get-web-editor-url /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/jobs/webEditor Possible warning codes are: - `NOT_ACCEPTED_BY_LINGUIST` - Job is not accepted by linguist - `NOT_ASSIGNED_TO_LINGUIST` - Job is not assigned to linguist - `PDF` - One of requested jobs is PDF - `PREVIOUS_WORKFLOW_NOT_COMPLETED` - Previous workflow step is not completed - `PREVIOUS_WORKFLOW_NOT_COMPLETED_STRICT` - Previous workflow step is not completed and project has strictWorkflowFinish set to true - `IN_DELIVERED_STATE` - Jobs in DELIVERED state - `IN_COMPLETED_STATE` - Jobs in COMPLETED state - `IN_REJECTED_STATE` - Jobs in REJECTED state Possible error codes are: - `ASSIGNED_TO_OTHER_USER` - Job is accepted by other user - `NOT_UNIQUE_TARGET_LANG` - Requested jobs contains different target locales - `TOO_MANY_SEGMENTS` - Count of requested job's segments is higher than **40000** - `TOO_MANY_JOBS` - Count of requested jobs is higher than **290** - `COMPLETED_JOINED_WITH_OTHER` - Jobs in COMPLETED state cannot be joined with jobs in other states - `DELIVERED_JOINED_WITH_OTHER` - Jobs in DELIVERED state cannot be joined with jobs in other states - `REJECTED_JOINED_WITH_OTHER` - Jobs in REJECTED state cannot be joined with jobs in other states Warning response example: ``` { "warnings": [ { "message": "Not accepted by linguist", "args": { "jobs": [ "abcd1234" ] }, "code": "NOT_ACCEPTED_BY_LINGUIST" }, { "message": "Previous workflow step not completed", "args": { "jobs": [ "abcd1234" ] }, "code": "PREVIOUS_WORKFLOW_NOT_COMPLETED" } ], "url": "/web/job/abcd1234-efgh5678/translate" } ``` Error response example: Status: `400 Bad Request` ``` { "errorCode": "NOT_UNIQUE_TARGET_LANG", "errorDescription": "Only files with identical target languages can be joined", "errorDetails": [ { "code": "NOT_UNIQUE_TARGET_LANG", "args": { "targetLocales": [ "de", "en" ] }, "message": "Only files with identical target languages can be joined" }, { "code": "TOO_MANY_SEGMENTS", "args": { "maxSegments": 40000, "segments": 400009 }, "message": "Up to 40000 segments can be opened in the CAT Web Editor, job has 400009 segments" } ] } ``` # List jobs Source: https://developers.phrase.com/en/api/tms/latest/job/list-jobs /openapi/phrase-tms-latest.json get /api2/v2/projects/{projectUid}/jobs API call to return a paginated list of [jobs](https://support.phrase.com/hc/en-us/articles/5709686763420-Jobs-TMS-) in the given project. Use the query parameters to further narrow down the searching criteria. - **pageNumber** - A zero-based parameter indicating the page number you wish to retrieve. The total number of pages is returned in each response in the `totalPages` field in the top level of the response. - **pageSize** - A parameter indicating the size of the page you wish to return. This has direct effect on the `totalPages` retrieved in each response and can hence influence the number of times to iterate over to get all the jobs. - **count** - When set to `true`, the response will not contain the list of jobs (the `content` field) but only the counts of elements and pages. Can be used to quickly retrieve the number of elements and pages to iterate over. - **workflowLevel** - A non-zero based parameter indicating which [workflow steps](https://support.phrase.com/hc/en-us/articles/5709717879324-Workflow-TMS-) the returned jobs belong to. If left unspecified, its value is set to 1. - **status** - A parameter allowing for filtering only for jobs in a specific status. - **assignedUser** - A parameter allowing for filtering only for jobs assigned to a specific user. The parameter accepts a user ID. - **dueInHours** - A parameter allowing for filtering only for jobs whose due date is less or equal to the number of hours specified. This does not exclude jobs by status - jobs already `DELIVERED`, `COMPLETED`, `CANCELLED`, `DECLINED` or `REJECTED` are still matched. Combine with `status` (excluding `DELIVERED`, `COMPLETED`, `CANCELLED`, `DECLINED` and `REJECTED`) to match the product's "overdue" definition. - **filename** - A parameter allowing for filtering only for jobs with a specific file name. - **targetLang** - A parameter allowing for filtering only for jobs with a specific target language. - **assignedVendor** - A parameter allowing for filtering only for jobs assigned to a specific vendor. The parameter accepts a user ID. - **notReady** - A parameter allowing for filtering only jobs that have been imported. When set to `true` the response will only contain jobs that have not been imported yet. This will also return jobs that have not been imported correctly, e.g. due to an error. For jobs assigned to one user across all projects, use GET /api2/v1/users/{userUid}/jobs instead. # Pseudo-translate job Source: https://developers.phrase.com/en/api/tms/latest/job/pseudo-translate-job /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/jobs/pseudoTranslate # Pseudo-translates job Source: https://developers.phrase.com/en/api/tms/latest/job/pseudo-translates-job /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/pseudoTranslate # Re-import remote file targets to selected jobs Source: https://developers.phrase.com/en/api/tms/latest/job/re-import-remote-file-targets-to-selected-jobs /openapi/phrase-tms-latest.json post /api2/v3/projects/{projectUid}/jobs/reimportTarget Re-imports the target file of the selected jobs from the connector/online-repository they originally came from. Jobs are silently skipped and omitted from the response in any of these cases: - The job was not sourced from a connector/online-repository (no remote file). - The job's connector type does not support target reimport — currently only `PHRASE`. Jobs sourced from other connector types (e.g. GitHub, GitLab, Sitecore, WordPress, Git) are always skipped. - The job was never exported to the online repository — a prior successful export is required before its target can be re-imported. **Response:** `jobs` contains only the subset of the requested jobs that were actually re-imported — it is not an echo of the request. Jobs skipped for any of the reasons above are omitted without any error being raised. # Re-import remote files to selected jobs Source: https://developers.phrase.com/en/api/tms/latest/job/re-import-remote-files-to-selected-jobs /openapi/phrase-tms-latest.json post /api2/v3/projects/{projectUid}/jobs/reimport Re-imports the source file of the selected jobs from the connector/online-repository they originally came from. Jobs that were not sourced from a connector (no remote file) are silently skipped and omitted from the response. **Precondition:** None of the selected jobs may be split. If any job is split, the whole request fails with `400 REIMPORT_FROM_ONLINE_REPOSITORY_NOT_ALLOWED` and no job is re-imported. **Response:** `jobs` contains only the subset of the requested jobs that were actually re-imported — it is not an echo of the request. Jobs skipped because they have no connector/online-repository source are omitted without any error being raised. # Search job's translation memories Source: https://developers.phrase.com/en/api/tms/latest/job/search-jobs-translation-memories /openapi/phrase-tms-latest.json post /api2/v3/projects/{projectUid}/jobs/{jobUid}/transMemories/search Results are scoped to the readable translation memories assigned to the job for its current workflow step. Access requires at least the Linguist role; lower roles are blocked. # Split job Source: https://developers.phrase.com/en/api/tms/latest/job/split-job /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/split Splits job by one of the following methods: * **After specific segments** - fill in `segmentOrdinals` * **Into X parts** - fill in `partCount` * **Into parts with specific size** - fill in `partSize`. partSize represents segment count in each part. * **Into parts with specific word count** - fill in `wordCount` * **By document parts** - fill in `byDocumentPart`, works only with **PowerPoint** files Only one option at a time is allowed. Use `splitAllWorkflowSteps` to split in all workflow steps (default: false). When enabled, the split operation will be applied to all sibling job parts across all workflow steps in the project. # Wildcard search job's translation memories Source: https://developers.phrase.com/en/api/tms/latest/job/wildcard-search-jobs-translation-memories /openapi/phrase-tms-latest.json post /api2/v3/projects/{projectUid}/jobs/{jobUid}/transMemories/wildCardSearch Results are scoped to the readable translation memories assigned to the job for its current workflow step. Access requires at least the Linguist role; lower roles are blocked. # List of Language AI profiles Source: https://developers.phrase.com/en/api/tms/latest/language-ai/list-of-language-ai-profiles /openapi/phrase-tms-latest.json get /api2/v1/memsourceTranslateProfiles Returns a paginated list of Language AI (MT) profiles for the authenticated organization. Use the returned profile `uid` values to assign a profile to a project or to retrieve its attached MT engines. A Language AI profile groups one or more MT (Machine Translation) engines under a named configuration that can be shared across projects. Two profile kinds exist: PLAI (Phrase Language AI), the standard multi-engine profile, and QUOKKA, a single-engine profile with a fixed neural MT model shape. Accessible to users with the Administrator or Project Manager role; also callable by Language AI platform apps. Returns an empty list when Language AI profiles are not enabled for the organization rather than a 403 error. The `pageSize` parameter accepts values between 1 and 50; requests outside that range are rejected with 400. # Search language assets Source: https://developers.phrase.com/en/api/tms/latest/language-assets/search-language-assets /openapi/phrase-tms-latest.json post /api2/v1/languageAssets/search Search across term bases and translation memories for matching language assets. **Search behavior:** - Translation memories: returns only 100% (exact) and 101% (in-context) matches. No fuzzy, wildcard, or sub-segment matching is supported. - Term bases: returns only approved terms matching the search text. No wildcard or partial matching. **Request limits:** - Max 50 queries per request, each up to 1000 characters. - Up to 100 translation memories and 100 term bases are searched. - Up to 10 TM matches returned per query text. - Optional `clientId` restricts to assets assigned to that client (or unassigned). **Execution:** - TM and TB searches run in parallel with a 20-second timeout. - Partial results are returned if one search times out or fails. - Check `metadata.tmSearchStatus` / `metadata.tbSearchStatus` (COMPLETED, TIMED_OUT, FAILED). - Returns HTTP 503 when the service is under heavy load. # Discard multiple finished LQA Assessment results Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/discard-multiple-finished-lqa-assessment-results /openapi/phrase-tms-latest.json delete /api2/v1/lqa/assessments/scorings # Discard multiple ongoing LQA Assessments Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/discard-multiple-ongoing-lqa-assessments /openapi/phrase-tms-latest.json delete /api2/v1/lqa/assessments Discards ongoing Language Quality Assessment (LQA) assessments for the given job parts in a single request. An assessment must be in the ongoing (started) state to be discarded; assessments that have not been started are silently skipped — no error is returned for them. Discarding is irreversible: discarded assessments cannot be resumed or recovered. Depending on your organization settings, job parts may be required to belong to the same project and workflow step; if that constraint is enforced, mixing job parts from different projects or steps returns 400. Use this endpoint to cancel in-progress assessments when a translation job is no longer needed. The request body must contain between 1 and 100 job part UIDs. # Discard ongoing LQA Assessment Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/discard-ongoing-lqa-assessment /openapi/phrase-tms-latest.json delete /api2/v1/lqa/assessments/{jobUid} Discards the in-progress Language Quality Assessment (LQA) for the specified job, removing all recorded issues and resetting the assessment state. Use this when an assessment was started in error or needs to be restarted from scratch. The operation is synchronous and returns 204 No Content immediately on success. Calling this endpoint when no assessment is in progress is safe. The caller must have edit permission on the job. When the project uses auto-LQA mode, only users belonging to the same organization as the job may discard assessments. | HTTP status | Condition | |-------------|----------------------------------------------------------------------------------------| | 204 | Assessment discarded successfully, or no assessment was in progress. | | 403 | Caller lacks edit permission on the job, or belongs to a different organization in | | | auto-LQA mode. Verify the token has sufficient privileges and retry. | | 404 | No job with the supplied UID exists or is visible to the caller. Check the UID value. | # Download LQA Assessment XLSX reports Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/download-lqa-assessment-xlsx-reports /openapi/phrase-tms-latest.json get /api2/v1/lqa/assessments/reports Use this endpoint to export completed Language Quality Assessment (LQA) results as XLSX files for offline review, auditing, or integration with external quality management tools. Each XLSX report corresponds to one job part that has passed through an LQA workflow step in Phrase TMS. When a single matching job part is found, the response is a single XLSX file. When multiple matching job parts are found, the response is a ZIP archive containing one XLSX file per job part. The response Content-Type is always application/octet-stream; the actual file format is conveyed by the filename extension in the Content-Disposition header. If a given job part has not yet reached an LQA workflow step, reports from the next successive workflow step that has results may be returned instead. If no downloadable reports are found for any of the provided job part UIDs, the endpoint returns 404. Linguist users can only download reports when the project security settings permit it and LQA is enabled for the organization. The returned filename is deterministic and cannot be customized through any request parameter. For a single job part it is LQA_{projectName}_{sourceLang}_{targetLang}_{jobFileName}.xlsx, with the full pre-extension string truncated to 250 characters. For multiple job parts it is LQA_{projectName}_{id}.zip, where {id} is an internal LQA-service batch identifier, not a project-level one. The only way to influence the filename is to rename the project or the job file before generating the report. # Edit multiple LQA assessments Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/edit-multiple-lqa-assessments /openapi/phrase-tms-latest.json put /api2/v1/lqa/assessments/edit Marks assessments for the given as edited # Finish LQA Assessment Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/finish-lqa-assessment /openapi/phrase-tms-latest.json put /api2/v1/lqa/assessments/{jobUid}/scorings Finishing LQA Assessment will calculate score # Finish multiple LQA Assessments Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/finish-multiple-lqa-assessments /openapi/phrase-tms-latest.json put /api2/v1/lqa/assessments/scorings Finishing LQA Assessments will calculate scores # Get LQA Assessment Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/get-lqa-assessment /openapi/phrase-tms-latest.json get /api2/v1/lqa/assessments/{jobUid} Retrieves the Language Quality Assessment (LQA) status and results for a single job. Use this endpoint after a reviewer finishes an LQA workflow step to read the MQM (Multidimensional Quality Metrics)-based score, issue counts by severity, and the pass/fail determination before advancing the job to the next step. If the requested job is not in an LQA workflow step, the assessment from the nearest successive LQA-enabled step is returned instead. The caller must have read access to the job's project. Roles without project visibility receive a 403 response (`FORBIDDEN`). To resolve a 403, ensure your API token belongs to a user with at least read access to the project containing this job. To resolve a 404 (`ResourceNotFound`), verify the jobUid is correct and the job has not been deleted or archived. Note: the example response is abbreviated for readability; the full response includes all fields such as `issueCounts` (with `criticalRepeated`, `majorRepeated`, `minorRepeated`, `neutralRepeated`) and `lqaProfile` (with `errorCategories`, `penaltyPoints`, `passFailThreshold`, `dateCreated`, `organization`). # Get LQA Assessment results Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/get-lqa-assessment-results /openapi/phrase-tms-latest.json post /api2/v1/lqa/assessments/results Returns Language Quality Assessment (LQA) scoring results for one or more job parts. Each result includes the score as a percentage (0–100), a PASS or FAIL verdict based on the project's configured LQA threshold, and a breakdown of issue counts by severity. Use this endpoint after assessments have been completed to retrieve scores for reporting or downstream automation. Job parts with no completed assessment are omitted from the response. Accepts between 1 and 100 job part UIDs per request. Errors: | Code | Condition | Action | |------|-----------|--------| | 400 BAD_REQUEST | The request body is missing, jobParts is empty, or exceeds 100 UIDs. | Verify the request body is present and that jobParts has between 1 and 100 entries. | | 403 FORBIDDEN | The caller lacks read access to one or more job parts. | Confirm the authenticated user has view permission on all requested job parts. | | 404 NOT_FOUND | One or more job part UIDs do not exist. | Verify all UIDs refer to existing job parts. | # Get multiple LQA Assessments Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/get-multiple-lqa-assessments /openapi/phrase-tms-latest.json post /api2/v1/lqa/assessments Returns Assessment results for given jobs. If any given job is not from LQA workflow step, result from successive workflow steps may be returned # Get recipients of email with LQA reports Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/get-recipients-of-email-with-lqa-reports /openapi/phrase-tms-latest.json get /api2/v1/lqa/assessments/reports/recipients # Get sharable link of LQA reports Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/get-sharable-link-of-lqa-reports /openapi/phrase-tms-latest.json get /api2/v1/lqa/assessments/reports/link Returns exactly one time-limited download link covering all the supplied job parts — never one link per job part. The link resolves to a single XLSX when the request contains exactly one job part, or a single ZIP archive (one XLSX per job part) when it contains more than one. # Send email(s) with LQA reports Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/send-emails-with-lqa-reports /openapi/phrase-tms-latest.json post /api2/v1/lqa/assessments/reports/emails Sends LQA (Language Quality Assessment) report emails to one or more recipients for the specified job parts. Use this to notify reviewers or project stakeholders when assessments are complete and the report is ready for review. The service generates exactly one time-limited download link for the entire request — never one link per job part — from the completed LQA reports for the supplied job parts, and attaches it to the outgoing email. This holds even when the email template repeats content per job part, for example via the {jobInfo}...{/jobInfo} loop macro: every repetition resolves to the same single link. The link is a single XLSX when exactly one job part is supplied, or a single ZIP archive (one XLSX per job part) when more than one job part is supplied. The link expires after 5 days by default. Each request may target up to 100 job parts and 100 recipient users; all job parts must belong to the same project. When organizationEmailTemplate is supplied, its body is used as the email template; the optional message field replaces the template body when both are provided, or is inserted into the default email template when no organizationEmailTemplate is given. If subject is provided it must be at least 1 character; null uses the default subject from the template. The ccAddress and bccAddress fields must be valid email addresses. Requires the Administrator or Project Manager role. Returns 404 when none of the specified job parts have a downloadable LQA report. # Start LQA Assessment Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/start-lqa-assessment /openapi/phrase-tms-latest.json post /api2/v1/lqa/assessments/{jobUid} Starts a Language Quality Assessment (LQA) for a single job part identified by its unique identifier (UID). LQA evaluates translation quality against the profile assigned to the job part's workflow step, scoring errors by category and severity in line with MQM (Multidimensional Quality Metrics) methodology. Use this endpoint after a job part has been translated and is ready for linguistic review. The returned profile captures the error categories, severity weights, and pass/fail threshold that reviewers will apply when annotating the assessment. If an assessment is already in progress or finished for the given job part, the existing assessment is discarded and a new one is started. All previously recorded errors are lost; this operation is not safe to retry without accepting data loss. **Error conditions:** - **400 Bad Request** — LQA is not configured for the job part's workflow step. Configure LQA for the workflow step in the project settings before starting an assessment. - **403 Forbidden (Auto LQA enabled)** — The project has Automatic LQA enabled. Disable Auto LQA in the project settings to use manual assessments. - **403 Forbidden (insufficient permission)** — The caller does not have edit permission on the job part. Request edit access from a project manager or administrator. - **404 Not Found** — No job part exists for the provided UID. Verify the jobUid is correct and belongs to a project accessible to the caller. # Start multiple LQA Assessments Source: https://developers.phrase.com/en/api/tms/latest/language-quality-assessment/start-multiple-lqa-assessments /openapi/phrase-tms-latest.json put /api2/v1/lqa/assessments Starts LQA assessments for the given job parts. If any of them have the assessment already started or finished, they are left unchanged. # Create new machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/create-new-machine-translate-settings /openapi/phrase-tms-latest.json post /api2/v1/machineTranslateSettings To add required secrets for each type use endpoint - [Set up secrets](#operation/setUpMachineTranslateSettingsSecrets) Adding secrets to Google AutoML use - [Set up Google AutoML secrets](#operation/uploadAccountKeyFileForGoogleAutoMl) # Delete machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/delete-machine-translate-settings /openapi/phrase-tms-latest.json delete /api2/v1/machineTranslateSettings/{mtsUid} Deletion is a no-op for Language AI profile wrapper engines (MemsourceTranslateSettings); the request succeeds with 204 but no data is removed. # Get machine Google AutoML labels Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/get-machine-google-automl-labels /openapi/phrase-tms-latest.json get /api2/v1/machineTranslateSettings/{mtsUid}/labels # Get machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/get-machine-translate-settings /openapi/phrase-tms-latest.json get /api2/v1/machineTranslateSettings/{mtsUid} Accessible to project managers without the 'Modify Server Setup' right. # Get machine translate settings secrets Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/get-machine-translate-settings-secrets /openapi/phrase-tms-latest.json get /api2/v1/machineTranslateSettings/{mtsUid}/secrets # Get machine translate settings types Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/get-machine-translate-settings-types /openapi/phrase-tms-latest.json get /api2/v1/machineTranslateSettings/types Returns valid type strings for POST /machineTranslateSettings (e.g. GoogleTranslate, AMAZON). Call this before creating a new MT engine to discover supported types. Accessible to project managers without the 'Modify Server Setup' right. # Get status of machine translate engine Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/get-status-of-machine-translate-engine /openapi/phrase-tms-latest.json get /api2/v1/machineTranslateSettings/{mtsUid}/status # List machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/list-machine-translate-settings /openapi/phrase-tms-latest.json get /api2/v1/machineTranslateSettings Accessible to project managers without the 'Modify Server Setup' right. # List third party machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/list-third-party-machine-translate-settings /openapi/phrase-tms-latest.json get /api2/v1/machineTranslateSettings/thirdPartyEngines Accessible to project managers without the 'Modify Server Setup' right. # Set up Google AutoML labels Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/set-up-google-automl-labels /openapi/phrase-tms-latest.json put /api2/v1/machineTranslateSettings/{mtsUid}/labels # Set up machine translate settings secrets Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/set-up-machine-translate-settings-secrets /openapi/phrase-tms-latest.json put /api2/v1/machineTranslateSettings/{mtsUid}/secrets It is possible to only add secrets to existing settings with corresponding secrets type e.g it is possible to add only Amazon specific secrets to the Amazon type settings. You should also use this method for updating secrets for settings # Update machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/update-machine-translate-settings /openapi/phrase-tms-latest.json put /api2/v1/machineTranslateSettings/{mtsUid} You can update existing settings ONLY with settings with the same type. It is forbidden to change type of settings using this API operation. # Upload service account key for Google AutoML Source: https://developers.phrase.com/en/api/tms/latest/machine-translation-settings/upload-service-account-key-for-google-automl /openapi/phrase-tms-latest.json put /api2/v1/machineTranslateSettings/{mtsUid}/secrets/upload For file in the request body provide also the filename in Content-Disposition header. # Translate with MT Source: https://developers.phrase.com/en/api/tms/latest/machine-translation/translate-with-mt /openapi/phrase-tms-latest.json post /api2/v1/machineTranslations/{mtSettingsUid}/translate Sends one or more source strings to the machine translation (MT) engine identified by the MT settings UID and returns the translated strings in the same order as the input. This call is synchronous — the response contains the translations directly, not a job reference. Use this endpoint to obtain on-demand MT output outside of a translation job, for example to pre-translate content in a custom workflow or to compare output quality across configured MT settings. The MT settings identified by mtSettingsUid must belong to the same organization as the authenticated user. If the MT engine type has been retired for the organization's pricing plan, the call returns 400. **Errors:** | HTTP status | errorCode | Cause | Remediation | |---|---|---|---| | 400 | BAD_REQUEST | Request body is malformed, a required field is missing, a language code is not a valid locale, sourceTexts is empty, or the MT engine type is retired for this plan. | Verify that from and to are valid language codes, sourceTexts contains at least one string, and the MT settings refer to an active engine type. | | 403 | AuthAccessDenied | The authenticated user does not belong to the same organization as the MT settings. | Use MT settings that belong to your organization. | | 404 | ResourceNotFound | No MT settings exist for the provided mtSettingsUid. | Check the UID value; retrieve valid UIDs from the MT settings list endpoint. | # Returns mapping for taskId (mxliff) Source: https://developers.phrase.com/en/api/tms/latest/mapping/returns-mapping-for-taskid-mxliff /openapi/phrase-tms-latest.json get /api2/v1/mappings/tasks/{id} Requires view right on the Job. workflowLevel defaults to 1 (range 1-15). # Clone net rate scheme Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/clone-net-rate-scheme /openapi/phrase-tms-latest.json post /api2/v1/netRateSchemes/{netRateSchemeUid}/clone Creates a copy of the net rate scheme identified by its UID, including all of its workflow-step rate settings. The clone is never marked as the organization default. Returns 200 (not 201) because the created DTO is returned directly. Non-translatable (NT) rate fields are returned as zero when the organization edition does not include the non-translatables-in-analyses feature. Requires an internal role (Admin or Project Manager) with the setup-server right; the scheme must belong to the caller's organization. # Create net rate scheme Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/create-net-rate-scheme /openapi/phrase-tms-latest.json post /api2/v2/netRateSchemes # Delete net rate scheme Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/delete-net-rate-scheme /openapi/phrase-tms-latest.json delete /api2/v1/netRateSchemes/{netRateSchemeUid} Deletes the net rate scheme identified by its UID. Requires an internal role (Admin or Project Manager) with the setup-server right; the scheme must belong to the caller's organization. # Edit net rate scheme Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/edit-net-rate-scheme /openapi/phrase-tms-latest.json put /api2/v2/netRateSchemes/{netRateSchemeUid} # Edit scheme for workflow step Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/edit-scheme-for-workflow-step /openapi/phrase-tms-latest.json put /api2/v1/netRateSchemes/{netRateSchemeUid}/workflowStepNetSchemes/{netRateSchemeWorkflowStepId} Updates the workflow-step-specific rates of the given net rate scheme. Non-translatable (NT) rate fields are returned as zero when the organization edition does not include the non-translatables-in-analyses feature. Requires an internal role (Admin or Project Manager) with the setup-server right; the scheme must belong to the caller's organization. # Get net rate scheme Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/get-net-rate-scheme /openapi/phrase-tms-latest.json get /api2/v2/netRateSchemes/{netRateSchemeUid} # Get scheme for workflow step Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/get-scheme-for-workflow-step /openapi/phrase-tms-latest.json get /api2/v1/netRateSchemes/{netRateSchemeUid}/workflowStepNetSchemes/{netRateSchemeWorkflowStepId} Returns the workflow-step-specific rates of the given net rate scheme. Non-translatable (NT) rate fields are returned as zero when the organization edition does not include the non-translatables-in-analyses feature. Requires an internal role (Admin or Project Manager) with the setup-server right; the scheme must belong to the caller's organization. # List net rate schemes Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/list-net-rate-schemes /openapi/phrase-tms-latest.json get /api2/v1/netRateSchemes Returns a paged list of net rate scheme references for the caller's organization, ordered by creation date (newest first) by default; a saved per-user list sort, when present, takes precedence. Optional query parameters filter the result set. Requires an internal role (Admin or Project Manager). # List schemes for workflow step Source: https://developers.phrase.com/en/api/tms/latest/net-rate-scheme/list-schemes-for-workflow-step /openapi/phrase-tms-latest.json get /api2/v1/netRateSchemes/{netRateSchemeUid}/workflowStepNetSchemes Returns a paged list of the workflow-step rate references of the given net rate scheme. Requires an internal role (Admin or Project Manager); the scheme must belong to the caller's organization. # List notifications Source: https://developers.phrase.com/en/api/tms/latest/notifications/list-notifications /openapi/phrase-tms-latest.json get /api2/v1/notifications Returns notifications scoped to the currently authenticated user. Results are paginated and sorted by date created (DATE_CREATED). The response includes a responseTimestamp. Authentication is required; unauthenticated requests are rejected with 403 Forbidden. # Add language pairs Source: https://developers.phrase.com/en/api/tms/latest/price-list/add-language-pairs /openapi/phrase-tms-latest.json post /api2/v1/priceLists/{priceListUid}/priceSets # Clone price list Source: https://developers.phrase.com/en/api/tms/latest/price-list/clone-price-list /openapi/phrase-tms-latest.json post /api2/v1/priceLists/{priceListUid}/clone # Create price list Source: https://developers.phrase.com/en/api/tms/latest/price-list/create-price-list /openapi/phrase-tms-latest.json post /api2/v1/priceLists If isDefault is set to true, the default flag is cleared on all other price lists. # Delete price list Source: https://developers.phrase.com/en/api/tms/latest/price-list/delete-price-list /openapi/phrase-tms-latest.json delete /api2/v1/priceLists/{priceListUid} # Edit minimum prices Source: https://developers.phrase.com/en/api/tms/latest/price-list/edit-minimum-prices /openapi/phrase-tms-latest.json post /api2/v1/priceLists/{priceListUid}/priceSets/minimumPrices Applies the minimum price to all language pairs for the given source and target language filters. # Edit prices Source: https://developers.phrase.com/en/api/tms/latest/price-list/edit-prices /openapi/phrase-tms-latest.json post /api2/v1/priceLists/{priceListUid}/priceSets/prices If object contains only price, all languages and workflow steps will be updated. # Export translation price list Source: https://developers.phrase.com/en/api/tms/latest/price-list/export-translation-price-list /openapi/phrase-tms-latest.json get /api2/v1/priceLists/{priceListUid}/export Returns the price list as a binary XLSX file. # Export translation price list template Source: https://developers.phrase.com/en/api/tms/latest/price-list/export-translation-price-list-template /openapi/phrase-tms-latest.json get /api2/v1/priceLists/exportTemplate Returns an empty price list template as a binary XLSX file. # Get price list Source: https://developers.phrase.com/en/api/tms/latest/price-list/get-price-list /openapi/phrase-tms-latest.json get /api2/v1/priceLists/{priceListUid} # Import translation price list Source: https://developers.phrase.com/en/api/tms/latest/price-list/import-translation-price-list /openapi/phrase-tms-latest.json post /api2/v1/priceLists/{priceListUid}/import Returns a parsed preview with per-row validation errors. Prices are not persisted. # List price lists Source: https://developers.phrase.com/en/api/tms/latest/price-list/list-price-lists /openapi/phrase-tms-latest.json get /api2/v1/priceLists # List price sets Source: https://developers.phrase.com/en/api/tms/latest/price-list/list-price-sets /openapi/phrase-tms-latest.json get /api2/v1/priceLists/{priceListUid}/priceSets # Remove language pair Source: https://developers.phrase.com/en/api/tms/latest/price-list/remove-language-pair /openapi/phrase-tms-latest.json delete /api2/v1/priceLists/{priceListUid}/priceSets/{sourceLanguage}/{targetLanguage} # Remove language pairs Source: https://developers.phrase.com/en/api/tms/latest/price-list/remove-language-pairs /openapi/phrase-tms-latest.json delete /api2/v1/priceLists/{priceListUid}/priceSets # Update price list Source: https://developers.phrase.com/en/api/tms/latest/price-list/update-price-list /openapi/phrase-tms-latest.json put /api2/v1/priceLists/{priceListUid} If isDefault is set to true, the default flag is cleared on all other price lists. # Assign vendor Source: https://developers.phrase.com/en/api/tms/latest/project/assign-vendor /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/assignVendor To unassign Vendor from Project, use empty body: ``` {} ``` # Assigns providers from template Source: https://developers.phrase.com/en/api/tms/latest/project/assigns-providers-from-template /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/applyTemplate/{templateUid}/assignProviders Assigns the providers configured in the template's workflow steps to the project's jobs. The project does not need to have been created from this template via the API — a template is applicable to a project when the number of workflow steps configured on the template equals the number of workflow steps on the project (step types/order are not compared). This is commonly needed after creating a project from a template via the API (applyTemplate), since — unlike the UI — those API calls do not assign providers automatically. Jobs that will be skipped: * jobs in Assigned status * jobs that already has assignments * jobs that are not ready yet (import or update source is in progress) # Assigns providers from template (specific jobs) Source: https://developers.phrase.com/en/api/tms/latest/project/assigns-providers-from-template-specific-jobs /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/applyTemplate/{templateUid}/assignProviders/forJobParts Jobs that will be skipped: * jobs in Assigned status * jobs that already has assignments # Clone project Source: https://developers.phrase.com/en/api/tms/latest/project/clone-project /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/clone # Create custom field instances Source: https://developers.phrase.com/en/api/tms/latest/project/create-custom-field-instances /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/customFields # Delete project Source: https://developers.phrase.com/en/api/tms/latest/project/delete-project /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid} Deletes the specified project. - When `purge = false` (default): The project, along with all its jobs and analyses, is soft-deleted and moved to the recycle bin, where it remains recoverable until permanently removed. - When `purge = true`: The project, its jobs, and its analyses are marked for immediate permanent deletion and are not visible in the recycle bin. A background cleaner process will remove all related data as soon as possible. # Edit analyse settings Source: https://developers.phrase.com/en/api/tms/latest/project/edit-analyse-settings /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/analyseSettings # Edit custom field of project Source: https://developers.phrase.com/en/api/tms/latest/project/edit-custom-field-of-project /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/customFields/{fieldInstanceUid} # Edit custom fields of the project (batch) Source: https://developers.phrase.com/en/api/tms/latest/project/edit-custom-fields-of-the-project-batch /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/customFields # Edit project (partial: metadata, cost center, MT settings, workflow automation, archive) Source: https://developers.phrase.com/en/api/tms/latest/project/edit-project-partial:-metadata-cost-center-mt-settings-workflow-automation-archive /openapi/phrase-tms-latest.json patch /api2/v1/projects/{projectUid} Partial update — unlike PUT /api2/v3/projects/{projectUid} (full replace), only fields present in the request body are changed; omitted fields are left unchanged. Exception: if `projectWorkflowSettings` is provided, all of its fields (`completeUnassigned`, `propagateTranslationsToLowerWfDuringUpdateSource`) are replaced together — include both to avoid silently resetting the other to `false`. Also used to: archive a project (`archived` field — unarchive via PATCH /api2/v1/projects/{projectUid}/restore); assign a cost center; set machine translate settings project-wide or per target language; and enable workflow automation (`projectWorkflowSettings.completeUnassigned`) to auto-complete unassigned workflow steps on an active project regardless of its current status — this is the only endpoint that can change workflow automation on a live project (project templates use PUT /api2/v2/projectTemplates/{uid} instead). # Get analyse settings Source: https://developers.phrase.com/en/api/tms/latest/project/get-analyse-settings /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/analyseSettings # Get content group for project Source: https://developers.phrase.com/en/api/tms/latest/project/get-content-group-for-project /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/contentGroup Returns the content group linked to the project. Returns an empty response body if the project has no content group linked. Accessible to guests and linguists. # Get custom field of project Source: https://developers.phrase.com/en/api/tms/latest/project/get-custom-field-of-project /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/customFields/{fieldInstanceUid} # Get custom fields of project (page) Source: https://developers.phrase.com/en/api/tms/latest/project/get-custom-fields-of-project-page /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/customFields # Get project Source: https://developers.phrase.com/en/api/tms/latest/project/get-project /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid} This API call retrieves information specific to a project. The level of detail in the response varies based on the user's role. Admins, Project Managers, Vendors, Buyers, and Linguists receive different responses, detailed below. - Details about predefined system metadata, such as client, domain, subdomain, cost center, business unit, or status. Note that [Custom Fields](../custom-fields/lists-custom-fields), if added to projects, are not included here and require retrieval via a dedicated Custom Fields API call. Metadata exposed to Linguists or Vendors might differ from what's visible to Admins or Project Managers. - [Workflow Step](https://support.phrase.com/hc/en-us/articles/5709717879324-Workflow-TMS-) information, crucial for user or vendor assignments through APIs. When projects are created, each workflow step's global ID instantiates into a project-specific workflow step ID necessary for user assignments. Attempting to assign the global workflow step ID (found under Settings or via Workflow Step APIs) results in an error, as only the project-specific step can be assigned. - Progress information indicating the total number of jobs across all workflow steps in the project, alongside the proportion of completed and overdue jobs. # List assignable templates Source: https://developers.phrase.com/en/api/tms/latest/project/list-assignable-templates /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/assignableTemplates # List projects Source: https://developers.phrase.com/en/api/tms/latest/project/list-projects /openapi/phrase-tms-latest.json get /api2/v1/projects API call to retrieve a paginated list of projects. Contains a subset of information contained in [Get project](../project/get-project) API call. Utilize the query parameters below to refine the search criteria: - **name** - The full project name or a portion of it. For instance, using `name=GUI` or `name=02` will find projects named `GUI02`. - **clientId** - The client's ID within the system, not interchangeable with its UID. - **clientName** - The complete or partial name of the client. For example, using `clientName=GUI` or `clientName=02` will find projects associated with the client `GUI02`. - **businessUnitId** - The business unit's ID within the system, not interchangeable with its UID. - **businessUnitName** - The complete or partial name of the business unit. For instance, using `businessUnitName=GUI` or `businessUnitName=02` will find projects linked to the business unit `GUI02`. - **statuses** - A list of project statuses. When adding multiple statuses, include each as a dedicated query parameter, e.g., `statuses=ASSIGNED&statuses=COMPLETED`. - **domainId** - The domain's ID within the system, not interchangeable with its UID. Domain is the org-configurable field used to tag/categorize a project's content type, e.g. Marketing, Legal, Medical, Technical. - **domainName** - The complete or partial name of the domain, the org-configurable field used to tag/categorize a project's content type (e.g. Marketing, Legal, Medical, Technical). Using `domainName=GUI` or `domainName=02` will find projects associated with the domain `GUI02`. - **subDomainId** - The subdomain's ID within the system, not interchangeable with its UID. Subdomain further refines the domain's content-type/category classification. - **subDomainName** - The complete or partial name of the subdomain, used together with domain to further refine a project's content-type/category classification. For example, using `subDomainName=GUI` or `subDomainName=02` will find projects linked to the subdomain `GUI02`. - **costCenterId** - The cost center's ID within the system, not interchangeable with its UID. - **costCenterName** - The complete or partial name of the cost center. For instance, using `costCenterName=GUI` or `costCenterName=02` will find projects associated with the cost center `GUI02`. - **dueInHours** - Filter for jobs with due dates less than or equal to the specified number of hours. This filter does not exclude jobs by status - jobs already `DELIVERED`, `COMPLETED`, `CANCELLED`, `DECLINED` or `REJECTED` are still included. To match the product's "overdue"/"delayed" definition (as used e.g. in the Time dashboard), combine `dueInHours=-1` with `jobStatuses` excluding `DELIVERED`, `COMPLETED`, `CANCELLED`, `DECLINED` and `REJECTED`. - **createdInLastHours** - Filter for jobs created within the specified number of hours. - **ownerId** - The user ID who owns the project within the system, not interchangeable with its UID. - **jobStatuses** - A list of statuses for jobs within the projects. Include each status as a dedicated query parameter, e.g., `jobStatuses=ASSIGNED&jobStatuses=COMPLETED`. - **jobStatusGroup** - The name of the status group used to filter projects containing at least one job with the specified status, similar to the status filter in the Projects list for a Linguist user. - **buyerId** - The Buyer's ID. - **pageNumber** - Indicates the desired page number (zero-based) to retrieve. The total number of pages is returned in the `totalPages` field within each response. - **pageSize** - Indicates the page size, affecting the `totalPages` retrieved in each response and potentially influencing the number of iterations needed to obtain all projects. - **nameOrInternalId** - Specify either the project name or Internal ID (the sequence number in the project list displayed in the UI). - **includeArchived** - A boolean parameter to include archived projects in the search. - **archivedOnly** - A boolean search indicating whether only archived projects should be searched. # Set project content group Source: https://developers.phrase.com/en/api/tms/latest/project/set-project-content-group /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/contentGroup Sets the content group for the project, replacing any previously linked group. Returns the newly linked content group. Returns 422 Unprocessable Entity if the project already has style guides assigned. # Unlink project from content group Source: https://developers.phrase.com/en/api/tms/latest/project/unlink-project-from-content-group /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/contentGroup Idempotent — if the project has no content group linked, returns 204 No Content without error. # Clone project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/clone-project-template /openapi/phrase-tms-latest.json post /api2/v1/projectTemplates/{projectTemplateUid}/clone Creates a copy of a project template. All settings are cloned: source and target languages, workflow steps, translation memory and term base assignments, pre-translate settings, security settings, and custom fields. The cloned template receives a new unique identifier. Requires the **Project template — create** access right (ADMIN and PROJECT_MANAGER roles only). # Create custom field instances Source: https://developers.phrase.com/en/api/tms/latest/project-template/create-custom-field-instances /openapi/phrase-tms-latest.json post /api2/v1/projectTemplates/{projectTemplateUid}/customFields # Create project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/create-project-template /openapi/phrase-tms-latest.json post /api2/v1/projectTemplates Creates a project template by copying the settings of an existing project referenced by `project.uid`. The source language, target languages, and workflow steps of that project are inherited by the new template and returned in the response — they cannot be set directly in this request. To create a template with a specific source/target language or workflow, first create or find a project that already has those settings, then save it as a template via this endpoint. Alternatively, create the template with a placeholder project and then use `PUT /projectTemplates/{projectTemplateUid}` (or the `v2` equivalent) to set `sourceLang`, `targetLangs`, and `workFlowSettings` directly, or `PATCH /projectTemplates/{projectTemplateUid}` to set `sourceLang` and `targetLangs` — no source project with those settings is required. `project.uid` is required and must be the UID of an existing project; an unknown or placeholder value (for example `"null"`) returns 404. The `name` field in the request is stored and returned as `templateName` in the response. The response also contains a separate `name` field, which is inherited from the source project. # Delete custom field of project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/delete-custom-field-of-project-template /openapi/phrase-tms-latest.json delete /api2/v1/projectTemplates/{projectTemplateUid}/customFields/{fieldInstanceUid} # Delete project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/delete-project-template /openapi/phrase-tms-latest.json delete /api2/v1/projectTemplates/{projectTemplateUid} # Edit analyse settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-analyse-settings /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid}/analyseSettings # Edit custom field of project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-custom-field-of-project-template /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid}/customFields/{fieldInstanceUid} # Edit custom fields of the project template (batch) Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-custom-fields-of-the-project-template-batch /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid}/customFields # Edit project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-project-template /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid} Replaces all editable fields of the project template in a single call. **Full-replace semantics** This is a complete replacement of the template, not a partial update. Any editable field omitted from the request body is cleared or reset to its default — this applies to scalar fields (e.g., `dynamicTitle` resets to `null`) as well as arrays/objects (e.g., omitting `workFlowSettings` entirely deletes all per-step workflow configurations, provider assignments, and LQA profiles). To change one field without affecting the rest, first `GET` the current template and include its other fields unchanged in the `PUT` body. Unlike `POST /projectTemplates`, this endpoint accepts `sourceLang`, `targetLangs`, and `workFlowSettings` directly in the request body — no source project reference is required to set or change the template's source/target languages or workflow steps. **Workflow steps and provider assignments (`workFlowSettings`)** Each entry in `workFlowSettings` references a workflow step and configures: - `assignedTo` — per-target-language list of providers (user, vendor, or language AI app) for that step - `notifyProvider` — email notification settings for providers assigned to that step - `lqaProfile` — LQA profile applied at that step For templates without workflow steps, use the top-level `assignedTo` field to assign providers per target language instead. **Project workflow behavior (`projectWorkflowSettings`)** - `completeUnassigned` — when `true`, jobs with no assigned provider are automatically marked complete - `propagateTranslationsToLowerWfDuringUpdateSource` — when `true`, accepted translations propagate to lower workflow steps when the source is updated Removing a language from `targetLangs` discards all saved provider assignments for that language. # Edit project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-project-template-1 /openapi/phrase-tms-latest.json put /api2/v2/projectTemplates/{projectTemplateUid} Replaces all editable fields of the project template in a single call. **Full-replace semantics** This is a complete replacement of the template, not a partial update. Any editable field omitted from the request body is cleared or reset to its default — this applies to scalar fields (e.g., `dynamicTitle` resets to `null`) as well as arrays/objects (e.g., omitting `workFlowSettings` entirely deletes all per-step workflow configurations, provider assignments, and LQA profiles). To change one field without affecting the rest, first `GET` the current template and include its other fields unchanged in the `PUT` body. Unlike `POST /projectTemplates`, this endpoint accepts `sourceLang`, `targetLangs`, and `workFlowSettings` directly in the request body — no source project reference is required to set or change the template's source/target languages or workflow steps. Use `workFlowSettings` to configure per-step provider assignments (`assignedTo`), email notifications (`notifyProvider`), and LQA profiles (`lqaProfile`) for each workflow step. For templates without workflow steps, use the top-level `assignedTo` field instead. `projectWorkflowSettings.completeUnassigned` controls whether jobs with no assigned provider are automatically marked complete. `projectWorkflowSettings.propagateTranslationsToLowerWfDuringUpdateSource` controls whether accepted translations propagate to lower workflow steps when the source is updated. Removing a language from `targetLangs` discards all saved provider assignments for that language. # Edit project template access and security settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-project-template-access-and-security-settings /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid}/accessSettings # Edit project template import settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-project-template-import-settings /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid}/importSettings # Edit project template machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-project-template-machine-translate-settings /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid}/mtSettings This will erase all mtSettings per language for project template. To remove all machine translate settings from template call without a machineTranslateSettings parameter. Alternatively, pass machineTranslateSettingsPerLangs to update the given locales only, leaving machine translate settings of other locales untouched. If machineTranslateSettingsPerLangs is set while the template currently has a single machineTranslateSettings value applying to all locales (bulk mode), that bulk setting is copied onto every target locale not listed in machineTranslateSettingsPerLangs before being cleared, so their effective machine translate settings do not change as a side effect of switching modes. machineTranslateSettingsPerLangs takes precedence if both machineTranslateSettings and machineTranslateSettingsPerLangs are set. # Edit quality assurance settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-quality-assurance-settings /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid}/qaSettings Only checks listed in the request are updated; omitted checks keep their current settings. # Edit term bases in project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-term-bases-in-project-template /openapi/phrase-tms-latest.json put /api2/v1/projectTemplates/{projectTemplateUid}/termBases Requires the project template to have at least one source and one target language configured. # Edit translation memories Source: https://developers.phrase.com/en/api/tms/latest/project-template/edit-translation-memories /openapi/phrase-tms-latest.json put /api2/v2/projectTemplates/{projectTemplateUid}/transMemories If user wants to edit “All target languages” or “All workflow steps”, but there are already varied TM settings for individual languages or steps, then the user risks to overwrite these individual choices. # Get analyse settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-analyse-settings /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/analyseSettings # Get content group for project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-content-group-for-project-template /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/contentGroup Returns the content group linked to the project template. Returns an empty response body if the template has no content group linked. # Get custom field of project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-custom-field-of-project-template /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/customFields/{fieldInstanceUid} # Get custom fields of project template (page) Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-custom-fields-of-project-template-page /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/customFields # Get import settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-import-settings /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/importSettings # Get project template access and security settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-project-template-access-and-security-settings /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/accessSettings # Get project template, including who is assigned and provider assignments per workflow step Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-project-template-including-who-is-assigned-and-provider-assignments-per-workflow-step /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid} Returns current provider/assignee data for the template: `assignedTo` (per-target-language provider assignments, used when the template has no workflow steps) and `workflowSettings` (per-workflow-step provider assignments and settings, used when the template has workflow steps). Note: importSettings in response is deprecated and will be always null. # Get project template machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-project-template-machine-translate-settings /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/mtSettings # Get project template pre-translate settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-project-template-pre-translate-settings /openapi/phrase-tms-latest.json get /api2/v4/projectTemplates/{projectTemplateUid}/preTranslateSettings # Get quality assurance settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-quality-assurance-settings /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/qaSettings # Get style guides for project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-style-guides-for-project-template /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/styleGuides Returns the style guides associated with the project template per target locale. Resolved either from directly assigned style guide associations, or — when the template is linked to a content group — from the content group's style guides. # Get term bases Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-term-bases /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/termBases # Get translation memories Source: https://developers.phrase.com/en/api/tms/latest/project-template/get-translation-memories /openapi/phrase-tms-latest.json get /api2/v3/projectTemplates/{projectTemplateUid}/transMemories # List project template relevant translation memories Source: https://developers.phrase.com/en/api/tms/latest/project-template/list-project-template-relevant-translation-memories /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/transMemories/relevant # List project templates Source: https://developers.phrase.com/en/api/tms/latest/project-template/list-project-templates /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates API call to list [project templates](https://support.phrase.com/hc/en-us/articles/5709647439772-Project-Templates-TMS-). Use the query parameters below to refine your search criteria for project templates: - **name** - The full project template name or a portion of it. For example, using `name=GUI` or `name=02` will locate project templates named `GUI02`. - **clientId** - The client's ID within the system, not interchangeable with its UID. - **clientName** - The complete or partial name of the client. For instance, using `clientName=GUI` or `clientName=02` will find project templates associated with the client `GUI02`. - **ownerUid** - The user UID who owns the project template within the system, interchangeable with its ID. - **domainName** - The complete or partial name of the domain, the org-configurable field used to tag/categorize a project's content type (e.g. Marketing, Legal, Medical, Technical). Using `domainName=GUI` or `domainName=02` will find project templates associated with the domain `GUI02`. - **subDomainName** - The complete or partial name of the subdomain, used together with domain to further refine a project's content-type/category classification. For instance, using `subDomainName=GUI` or `subDomainName=02` will locate project templates linked to the subdomain `GUI02`. - **costCenterId** - The cost center's ID within the system, not interchangeable with its UID. - **costCenterName** - The complete or partial name of the cost center. For example, using `costCenterName=GUI` or `costCenterName=02` will find project templates associated with the cost center `GUI02`. - **businessUnitName** - The complete or partial name of the business unit. For instance, using `businessUnitName=GUI` or `businessUnitName=02` will locate project templates linked to the business unit `GUI02`. - **sort** - Determines if the resulting list of project templates should be sorted by their names or the date they were created. This field supports either `dateCreated` or `templateName` as values. - **direction** - Indicates the sorting order for the resulting list by using either `asc` (ascending) or `desc` (descending) values. - **pageNumber** - Indicates the desired page number (zero-based) to retrieve. The total number of pages is returned in the `totalPages` field within each response. - **pageSize** - Indicates the page size, affecting the `totalPages` retrieved in each response and potentially impacting the number of iterations needed to obtain all project templates. # Patch project template Source: https://developers.phrase.com/en/api/tms/latest/project-template/patch-project-template /openapi/phrase-tms-latest.json patch /api2/v1/projectTemplates/{projectTemplateUid} Partially updates a project template. Only the fields present in the request body are updated; omitted fields retain their current values. Unlike `POST /projectTemplates`, `sourceLang` and `targetLangs` can be set directly here — no source project reference is required to change the template's source/target languages. To clear a reference field (e.g. remove a client), send `{"uid": null}` for that field. `workflowSettings` is a whole-value replacement, not merged field-by-field: omit it to leave it untouched, but sending it replaces the settings for every workflow step (steps left out lose their settings). # Set project template content group Source: https://developers.phrase.com/en/api/tms/latest/project-template/set-project-template-content-group /openapi/phrase-tms-latest.json post /api2/v1/projectTemplates/{projectTemplateUid}/contentGroup Sets the content group for the project template, replacing any previously linked group. Returns the newly linked content group. Returns 422 Unprocessable Entity if the project template already has style guides assigned. # Unlink project template from content group Source: https://developers.phrase.com/en/api/tms/latest/project-template/unlink-project-template-from-content-group /openapi/phrase-tms-latest.json delete /api2/v1/projectTemplates/{projectTemplateUid}/contentGroup Idempotent — if the project template has no content group linked, returns 204 No Content without error. # Update project template pre-translate settings Source: https://developers.phrase.com/en/api/tms/latest/project-template/update-project-template-pre-translate-settings /openapi/phrase-tms-latest.json put /api2/v4/projectTemplates/{projectTemplateUid}/preTranslateSettings # Add target languages Source: https://developers.phrase.com/en/api/tms/latest/project/add-target-languages /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/targetLangs Add target languages to project # Add workflow steps Source: https://developers.phrase.com/en/api/tms/latest/project/add-workflow-steps /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/workflowSteps Adds one or more existing workflow steps to an existing project, i.e. a project that has already been created. This is distinct from creating workflow step definitions at the organization level (see POST /workflowSteps) or from configuring the workflow at project-template or project-creation time. Requires ADMIN or PROJECT_MANAGER role with edit rights on the project. Steps already assigned to the project are silently ignored. Returns 409 Conflict only if a concurrent request assigns the same step first. # Assign machine translate engine to project Source: https://developers.phrase.com/en/api/tms/latest/project/assign-machine-translate-engine-to-project /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/mtSettings Assigns an existing machine translate engine as the project-wide MT engine, replacing any project-level or per-language MT settings currently in effect. This will erase all mtSettings per language for the project. To remove all machine translate settings from the project, call without a machineTranslateSettings parameter. # Create project Source: https://developers.phrase.com/en/api/tms/latest/project/create-project /openapi/phrase-tms-latest.json post /api2/v3/projects # Create project from template Source: https://developers.phrase.com/en/api/tms/latest/project/create-project-from-template /openapi/phrase-tms-latest.json post /api2/v2/projects/applyTemplate/{templateUid} Note: unlike creating a project from a template via the UI, this API call does not automatically assign providers configured in the template's workflow steps. Call assignProviders separately to apply them. # Create project from template (async) Source: https://developers.phrase.com/en/api/tms/latest/project/create-project-from-template-async /openapi/phrase-tms-latest.json post /api2/v2/projects/applyTemplate/async/{templateUid} Note: unlike creating a project from a template via the UI, this API call does not automatically assign providers configured in the template's workflow steps. Call assignProviders separately to apply them. # Delete custom field of project Source: https://developers.phrase.com/en/api/tms/latest/project/delete-custom-field-of-project /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/customFields/{fieldInstanceUid} # Edit access and security settings Source: https://developers.phrase.com/en/api/tms/latest/project/edit-access-and-security-settings /openapi/phrase-tms-latest.json put /api2/v2/projects/{projectUid}/accessSettings # Edit financial settings Source: https://developers.phrase.com/en/api/tms/latest/project/edit-financial-settings /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/financialSettings # Edit machine translate settings per language Source: https://developers.phrase.com/en/api/tms/latest/project/edit-machine-translate-settings-per-language /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/mtSettingsPerLanguage This will erase mtSettings for project # Edit project Source: https://developers.phrase.com/en/api/tms/latest/project/edit-project /openapi/phrase-tms-latest.json put /api2/v3/projects/{projectUid} # Edit project import settings Source: https://developers.phrase.com/en/api/tms/latest/project/edit-project-import-settings /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/importSettings # Edit project status Source: https://developers.phrase.com/en/api/tms/latest/project/edit-project-status /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/setStatus # Edit quality assurance settings Source: https://developers.phrase.com/en/api/tms/latest/project/edit-quality-assurance-settings /openapi/phrase-tms-latest.json put /api2/v2/projects/{projectUid}/qaSettings Only checks listed in the request are updated; omitted checks keep their current settings. # Edit term bases Source: https://developers.phrase.com/en/api/tms/latest/project/edit-term-bases /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/termBases Replaces all existing term base assignments for the specified target language, or for all project target languages if targetLang is omitted. To assign a term base for write mode, include it in both readTermBases and writeTermBase. To assign a term base for quality assurance, include it in both readTermBases and qualityAssuranceTermBases. # Edit translation memories Source: https://developers.phrase.com/en/api/tms/latest/project/edit-translation-memories /openapi/phrase-tms-latest.json put /api2/v3/projects/{projectUid}/transMemories If user wants to edit “All target languages” or “All workflow steps”, but there are already varied TM settings for individual languages or steps, then the user risks to overwrite these individual choices. Each dataPerContext entry must either be a single entry with workflowStep omitted (applies to all workflow steps), or entries that all have workflowStep set (individual workflow steps). Combining an all-workflow-step entry with individual-workflow-step entries in the same request returns a 400 Bad Request. # Get access and security settings Source: https://developers.phrase.com/en/api/tms/latest/project/get-access-and-security-settings /openapi/phrase-tms-latest.json get /api2/v2/projects/{projectUid}/accessSettings # Get file naming settings for project Source: https://developers.phrase.com/en/api/tms/latest/project/get-file-naming-settings-for-project /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/fileNamingSettings # Get financial settings Source: https://developers.phrase.com/en/api/tms/latest/project/get-financial-settings /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/financialSettings # Get LQA settings Source: https://developers.phrase.com/en/api/tms/latest/project/get-lqa-settings /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/lqaSettings # Get project machine translate settings Source: https://developers.phrase.com/en/api/tms/latest/project/get-project-machine-translate-settings /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/mtSettings # Get project pre-translate settings Source: https://developers.phrase.com/en/api/tms/latest/project/get-project-pre-translate-settings /openapi/phrase-tms-latest.json get /api2/v4/projects/{projectUid}/preTranslateSettings # Get projects's default import settings Source: https://developers.phrase.com/en/api/tms/latest/project/get-projectss-default-import-settings /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/importSettings # Get QA checks Source: https://developers.phrase.com/en/api/tms/latest/project/get-qa-checks /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/qaSettingsChecks Returns enabled quality assurance settings. # Get style guides for project Source: https://developers.phrase.com/en/api/tms/latest/project/get-style-guides-for-project /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/styleGuides Returns the style guides associated with the project per target locale. Resolved either from directly assigned style guide associations, or — when the project is linked to a content group — from the content group's style guides. # Get suggested providers Source: https://developers.phrase.com/en/api/tms/latest/project/get-suggested-providers /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/providers/suggest # Get term bases Source: https://developers.phrase.com/en/api/tms/latest/project/get-term-bases /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/termBases # Get workflow steps Source: https://developers.phrase.com/en/api/tms/latest/project/get-workflow-steps /openapi/phrase-tms-latest.json get /api2/v2/projects/{projectUid}/workflowSteps # List analyses by project Source: https://developers.phrase.com/en/api/tms/latest/project/list-analyses-by-project /openapi/phrase-tms-latest.json get /api2/v3/projects/{projectUid}/analyses # List project providers Source: https://developers.phrase.com/en/api/tms/latest/project/list-project-providers /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/providers # List project relevant term bases Source: https://developers.phrase.com/en/api/tms/latest/project/list-project-relevant-term-bases /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/termBases/relevant # List project relevant translation memories Source: https://developers.phrase.com/en/api/tms/latest/project/list-project-relevant-translation-memories /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/transMemories/relevant # List quotes Source: https://developers.phrase.com/en/api/tms/latest/project/list-quotes /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/quotes # List translation memories assigned to project Source: https://developers.phrase.com/en/api/tms/latest/project/list-translation-memories-assigned-to-project /openapi/phrase-tms-latest.json get /api2/v3/projects/{projectUid}/transMemories Returns the translation memories currently configured/assigned to this project. This is not a recommendation of memories that could be relevant — see the separate '/relevant' endpoint for that. # Remove target languages Source: https://developers.phrase.com/en/api/tms/latest/project/remove-target-languages /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/targetLangs Remove target languages from project. Removal is blocked for a language if any of the following are present: - An active or trashed job (jobs in the recycle bin also block removal) - A translation memory assigned to the project for that language - A term base assigned to the project for that language All blocked languages are listed in the 400 error response. Removal is also blocked when it would leave the project with no target languages. # Restore project Source: https://developers.phrase.com/en/api/tms/latest/project/restore-project /openapi/phrase-tms-latest.json patch /api2/v1/projects/{projectUid}/restore Restores a project that was previously archived # Search translation memory for segment in the project Source: https://developers.phrase.com/en/api/tms/latest/project/search-translation-memory-for-segment-in-the-project /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/transMemories/searchSegmentInProject Returns at most maxSegments records with score >= scoreThreshold and at most maxSubsegments records which are subsegment, i.e. the source text is substring of the query text. # Update file naming settings for project Source: https://developers.phrase.com/en/api/tms/latest/project/update-file-naming-settings-for-project /openapi/phrase-tms-latest.json put /api2/v1/projects/{projectUid}/fileNamingSettings # Update project pre-translate settings (job-creation default) Source: https://developers.phrase.com/en/api/tms/latest/project/update-project-pre-translate-settings-job-creation-default /openapi/phrase-tms-latest.json put /api2/v4/projects/{projectUid}/preTranslateSettings Controls whether new jobs are automatically pre-translated when created (preTranslateOnJobCreation) and related project-level pre-translate defaults. This is distinct from POST .../jobs/preTranslate, which pre-translates already-created jobs on demand. # Upload Job Preview Package Source: https://developers.phrase.com/en/api/tms/latest/project/upload-job-preview-package /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobPreviewPackage Uploads a Job Preview Package to a project. ImportFile API then refers to the preview package. The package is a zip file containing the preview HTML and related asset (css, js..) files. # Get suggested providers Source: https://developers.phrase.com/en/api/tms/latest/provider/get-suggested-providers /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/jobs/{jobUid}/providers/suggest # Get suggested providers for multiple jobs Source: https://developers.phrase.com/en/api/tms/latest/provider/get-suggested-providers-for-multiple-jobs /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/jobs/providers/suggest Returns the providers most relevant to a selection of jobs in `relevant`, ranked by relevance aggregated across all selected jobs based on the jobs' languages, workflow steps and history. An optional `limit` caps the response to the top-N most relevant providers; if omitted, all are returned. # Add ignored warnings Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/add-ignored-warnings /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/qualityAssurances/ignoredWarnings # Add ignored warnings Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/add-ignored-warnings-1 /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/jobs/qualityAssurances/ignoredWarnings # Create LQA profile Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/create-lqa-profile /openapi/phrase-tms-latest.json post /api2/v1/lqa/profiles Requires LQA to be enabled for the organization. Requires internal role. # Delete ignored warnings Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/delete-ignored-warnings /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/jobs/{jobUid}/qualityAssurances/ignoredWarnings # Delete ignored warnings Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/delete-ignored-warnings-1 /openapi/phrase-tms-latest.json delete /api2/v2/projects/{projectUid}/jobs/qualityAssurances/ignoredWarnings # Delete LQA profile Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/delete-lqa-profile /openapi/phrase-tms-latest.json delete /api2/v1/lqa/profiles/{profileUid} Returns 400 if the profile is set as the organization default or is still assigned to a project or project template. Requires LQA to be enabled for the organization. Requires internal role. # Duplicate LQA profile Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/duplicate-lqa-profile /openapi/phrase-tms-latest.json post /api2/v1/lqa/profiles/{profileUid}/duplicate Creates a copy of the specified profile with a prefix added to the name. Requires LQA to be enabled for the organization. Requires internal role. # Edit ignored checks Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/edit-ignored-checks /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/qualityAssurances/ignoreChecks # Get list of LQA profile authors Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/get-list-of-lqa-profile-authors /openapi/phrase-tms-latest.json get /api2/v1/lqa/profiles/authors Requires LQA to be enabled for the organization. Accessible to users with internal role or projectCreate access right. # Get list of LQA profile authors Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/get-list-of-lqa-profile-authors-1 /openapi/phrase-tms-latest.json get /api2/v2/lqa/profiles/authors Requires LQA to be enabled for the organization. Requires internal role. # Get LQA profile default values Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/get-lqa-profile-default-values /openapi/phrase-tms-latest.json get /api2/v1/lqa/profiles/defaultValues Returns dummy default values, not a persisted profile. Requires LQA to be enabled for the organization. Accessible to users with internal role or projectCreate access right. # Get LQA profile details Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/get-lqa-profile-details /openapi/phrase-tms-latest.json get /api2/v1/lqa/profiles/{profileUid} Requires LQA to be enabled for the organization. Accessible to users with internal role or projectCreate access right. # Get QA settings for job part Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/get-qa-settings-for-job-part /openapi/phrase-tms-latest.json get /api2/v4/projects/{projectUid}/jobs/{jobUid}/qualityAssurances/settings Returns enabled quality assurance checks and settings for job. # Get QA settings for project Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/get-qa-settings-for-project /openapi/phrase-tms-latest.json get /api2/v4/projects/{projectUid}/jobs/qualityAssurances/settings Returns enabled quality assurance checks and settings. # List LQA profiles Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/list-lqa-profiles /openapi/phrase-tms-latest.json get /api2/v1/lqa/profiles Requires LQA to be enabled for the organization. Accessible to users with internal role or projectCreate access right. # Make LQA profile default Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/make-lqa-profile-default /openapi/phrase-tms-latest.json post /api2/v1/lqa/profiles/{profileUid}/default Sets this profile as the organization's default LQA profile. Requires LQA to be enabled for the organization. Requires internal role. # Run quality assurance (batch) Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/run-quality-assurance-batch /openapi/phrase-tms-latest.json post /api2/v4/projects/{projectUid}/jobs/qualityAssurances/run Call "Get QA settings" endpoint to get the list of enabled QA checks # Run quality assurance on selected segments Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/run-quality-assurance-on-selected-segments /openapi/phrase-tms-latest.json post /api2/v4/projects/{projectUid}/jobs/qualityAssurances/segments/run By default runs only fast running checks. Source and target language of jobs have to match. # Run quality assurance on selected segments and save segments Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/run-quality-assurance-on-selected-segments-and-save-segments /openapi/phrase-tms-latest.json post /api2/v4/projects/{projectUid}/jobs/qualityAssurances/segments/{segmentId}/runWithUpdate By default runs only fast running checks. # Run quality assurance v4 Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/run-quality-assurance-v4 /openapi/phrase-tms-latest.json post /api2/v4/projects/{projectUid}/jobs/{jobUid}/qualityAssurances/run Call "Get QA settings" endpoint to get the list of enabled QA checks # Update LQA profile Source: https://developers.phrase.com/en/api/tms/latest/quality-assurance/update-lqa-profile /openapi/phrase-tms-latest.json put /api2/v1/lqa/profiles/{profileUid} Requires LQA to be enabled for the organization. Requires internal role. # Get QE warnings for selected job parts Source: https://developers.phrase.com/en/api/tms/latest/quality-profile/get-qe-warnings-for-selected-job-parts /openapi/phrase-tms-latest.json post /api2/v1/qualityProfiles/qeWarnings Returns AI-generated quality estimation warnings for the selected job parts. Only call this after the async evaluation job started by POST /api2/v1/qualityProfiles/evaluate has completed (asyncResponse != null on GET /api2/v1/async/{asyncRequest.id}). Calling before completion returns empty segmentWarnings — this is not a clean result, it means the evaluation is still running. Each response covers up to 100 segments (fewer if the end of the scan range is reached). Pagination is cursor-based: omit `initialSegmentId` on the first request to start from the first segment; on subsequent requests, pass the last `segmentId` from the previous response's `segmentWarnings`. `endReached=true` signals there are no further segments. All job parts must belong to the same project and workflow step. # Store evaluation warnings for a job part Source: https://developers.phrase.com/en/api/tms/latest/quality-profile/store-evaluation-warnings-for-a-job-part /openapi/phrase-tms-latest.json post /api2/v1/qualityProfiles/segmentWarnings Stores segment-level quality evaluation warnings for the specified job part. Each segment's existing evaluation runs on the converter are overwritten with the provided results — prior history is not preserved. An empty results array for a segment records a passing run. Maximum 500 segments per request; larger sets must be split by the caller. Each warning's `type` field must not exceed 255 characters; `message` must not exceed 1000 characters. # Create quote Source: https://developers.phrase.com/en/api/tms/latest/quote/create-quote /openapi/phrase-tms-latest.json post /api2/v2/quotes For billingUnit "Hour", provide either workflowSettings or units, but not both. Additional workflow steps listed in additionalSteps are added to the quote by name. # Delete quote Source: https://developers.phrase.com/en/api/tms/latest/quote/delete-quote /openapi/phrase-tms-latest.json delete /api2/v1/quotes/{quoteUid} Deletes the quote. Requires the quote-edit project-space permission; project "delete other" permission alone is not sufficient. # Email quotes Source: https://developers.phrase.com/en/api/tms/latest/quote/email-quotes /openapi/phrase-tms-latest.json post /api2/v1/quotes/email Sends a quote summary email to providers. All referenced quotes must have a provider assigned. # Get quote Source: https://developers.phrase.com/en/api/tms/latest/quote/get-quote /openapi/phrase-tms-latest.json get /api2/v1/quotes/{quoteUid} # Create project reference files Source: https://developers.phrase.com/en/api/tms/latest/reference-file/create-project-reference-files /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/references The `json` request part allows sending additional data as JSON, such as a text note that will be used for all the given reference files. In case no `file` parts are sent, only 1 reference is created with the given note. Either at least one file must be sent or the note must be specified. Example: ``` { "note": "Sample text" } ``` Required role: Administrator, Project Manager, Guest, or Submitter. Maximum 50 files per request. Vendor organizations may create reference files only if `securitySettings.vendors.jobVendorsMayUploadReferences` is enabled on the project (see Get project). # Create project template reference files Source: https://developers.phrase.com/en/api/tms/latest/reference-file/create-project-template-reference-files /openapi/phrase-tms-latest.json post /api2/v1/projectTemplates/{projectTemplateUid}/references The `json` request part allows sending additional data as JSON, such as a text note that will be used for all the given reference files. In case no `file` parts are sent, only 1 reference is created with the given note. Either at least one file must be sent or the note must be specified. Example: ``` { "note": "Sample text" } ``` Required role: Administrator or Project Manager. Maximum 50 files per request. # Delete project reference files (batch) Source: https://developers.phrase.com/en/api/tms/latest/reference-file/delete-project-reference-files-batch /openapi/phrase-tms-latest.json delete /api2/v1/projects/{projectUid}/references Required role: Administrator, Project Manager, Guest, or Submitter. Vendor organizations may delete only their own files if the project security settings allow it (`securitySettings.vendors.jobVendorsMayUploadReferences`, see Get project). The underlying file in storage is deleted if no other reference points to it. # Delete project template reference files (batch) Source: https://developers.phrase.com/en/api/tms/latest/reference-file/delete-project-template-reference-files-batch /openapi/phrase-tms-latest.json delete /api2/v1/projectTemplates/{projectTemplateUid}/references Required role: Administrator or Project Manager. All reference files must belong to the same organization as the current user. The underlying file in storage is deleted if no other reference points to it. # Download project reference file Source: https://developers.phrase.com/en/api/tms/latest/reference-file/download-project-reference-file /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/references/{referenceFileId} # Download project reference files (batch) Source: https://developers.phrase.com/en/api/tms/latest/reference-file/download-project-reference-files-batch /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/references/download Returns a single file when one reference is selected, or a ZIP archive for multiple. Reference files are identified by integer ID (not UID). # Download project template reference file Source: https://developers.phrase.com/en/api/tms/latest/reference-file/download-project-template-reference-file /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/references/{referenceFileId} Accessible by Administrator, Project Manager, Guest, and Linguist roles. Returns 400 if the reference file does not belong to the specified project template. # Download project template reference files (batch) Source: https://developers.phrase.com/en/api/tms/latest/reference-file/download-project-template-reference-files-batch /openapi/phrase-tms-latest.json post /api2/v1/projectTemplates/{projectTemplateUid}/references/download Accessible by Administrator, Project Manager, Guest, and Linguist roles. Returns a single file when one reference is selected, or a ZIP archive for multiple. Returns 400 if any reference file does not belong to the specified project template. # List project reference file creators Source: https://developers.phrase.com/en/api/tms/latest/reference-file/list-project-reference-file-creators /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/references/creators The result is not paged and returns up to 50 users. If the requested user is not included, the search can be narrowed down with the `userName` parameter. # List project reference files Source: https://developers.phrase.com/en/api/tms/latest/reference-file/list-project-reference-files /openapi/phrase-tms-latest.json get /api2/v1/projects/{projectUid}/references # List project template reference files Source: https://developers.phrase.com/en/api/tms/latest/reference-file/list-project-template-reference-files /openapi/phrase-tms-latest.json get /api2/v1/projectTemplates/{projectTemplateUid}/references Accessible by Administrator, Project Manager, Guest, and Linguist roles. The `filename` parameter filters by substring match. The `createdBy` field in each result is null when the creator belongs to a different organization. # Create segmentation rule Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/create-segmentation-rule /openapi/phrase-tms-latest.json post /api2/v1/segmentationRules Creates a new segmentation rule from the streamed file and the segRule JSON object passed in the segRule header. The segRule header carries a JSON object with the fields name, locale, primary and filename (the same SegmentationRuleDto shape returned by the GET action). Requires an internal role (ADMIN or PROJECT_MANAGER) with the setupServer access right. # Delete segmentation rule Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/delete-segmentation-rule /openapi/phrase-tms-latest.json delete /api2/v1/segmentationRules/{segRuleUid} Deletes a segmentation rule and clears its references from converter import settings. Requires an internal role (ADMIN or PROJECT_MANAGER) with the setupServer access right. # Edit segmentation rule Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/edit-segmentation-rule /openapi/phrase-tms-latest.json put /api2/v1/segmentationRules/{segRuleUid} Requires an internal role (ADMIN or PROJECT_MANAGER) with the setupServer access right. # Export default segmentation rules Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/export-default-segmentation-rules /openapi/phrase-tms-latest.json get /api2/v1/segmentationRules/{locale}/exportDefault # Export segmentation rule Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/export-segmentation-rule /openapi/phrase-tms-latest.json get /api2/v1/segmentationRules/{segRuleUid}/export # Get owners of segmentation rules Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/get-owners-of-segmentation-rules /openapi/phrase-tms-latest.json get /api2/v1/segmentationRules/owners Requires an internal role (ADMIN or PROJECT_MANAGER). # Get segmentation rule Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/get-segmentation-rule /openapi/phrase-tms-latest.json get /api2/v1/segmentationRules/{segRuleUid} Requires an internal role (ADMIN or PROJECT_MANAGER). # List segmentation rules Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/list-segmentation-rules /openapi/phrase-tms-latest.json get /api2/v1/segmentationRules Lists segmentation rules of the organization. The language and languages parameters are mutually exclusive; providing both returns 400 Bad Request. The locales parameter is normalized before filtering. Requires an internal role (ADMIN or PROJECT_MANAGER). # Replace segmentation rule file Source: https://developers.phrase.com/en/api/tms/latest/segmentation-rules/replace-segmentation-rule-file /openapi/phrase-tms-latest.json put /api2/v1/segmentationRules/{segRuleUid}/file Replaces the file content of an existing segmentation rule, preserving its id and uid. Requires an internal role (ADMIN or PROJECT_MANAGER) with the setupServer access right. # Create service Source: https://developers.phrase.com/en/api/tms/latest/service/create-service /openapi/phrase-tms-latest.json post /api2/v1/services # Delete service Source: https://developers.phrase.com/en/api/tms/latest/service/delete-service /openapi/phrase-tms-latest.json delete /api2/v1/services/{serviceUid} # Delete services (batch) Source: https://developers.phrase.com/en/api/tms/latest/service/delete-services-batch /openapi/phrase-tms-latest.json delete /api2/v1/services # Edit service Source: https://developers.phrase.com/en/api/tms/latest/service/edit-service /openapi/phrase-tms-latest.json put /api2/v1/services/{serviceUid} Partial update — omitted fields retain their current values. # Get service Source: https://developers.phrase.com/en/api/tms/latest/service/get-service /openapi/phrase-tms-latest.json get /api2/v1/services/{serviceUid} # List services Source: https://developers.phrase.com/en/api/tms/latest/service/list-services /openapi/phrase-tms-latest.json get /api2/v1/services Requires ADMIN or PROJECT_MANAGER role with the Server Setup access right enabled. # Add word to dictionary Source: https://developers.phrase.com/en/api/tms/latest/spell-check/add-word-to-dictionary /openapi/phrase-tms-latest.json post /api2/v1/spellCheck/words # Spell check Source: https://developers.phrase.com/en/api/tms/latest/spell-check/spell-check /openapi/phrase-tms-latest.json post /api2/v1/spellCheck/check Spell check using the settings of the user's organization # Spell check for job Source: https://developers.phrase.com/en/api/tms/latest/spell-check/spell-check-for-job /openapi/phrase-tms-latest.json post /api2/v1/spellCheck/check/{jobUid} Spell check using the settings from the project of the job # Suggest a word Source: https://developers.phrase.com/en/api/tms/latest/spell-check/suggest-a-word /openapi/phrase-tms-latest.json post /api2/v1/spellCheck/suggest Spell check suggest using the users's spell check dictionary # Create subdomain Source: https://developers.phrase.com/en/api/tms/latest/subdomain/create-subdomain /openapi/phrase-tms-latest.json post /api2/v1/subDomains Requires the subDomainCreate access right. Subdomain names must be unique within the organization. # Delete subdomain Source: https://developers.phrase.com/en/api/tms/latest/subdomain/delete-subdomain /openapi/phrase-tms-latest.json delete /api2/v1/subDomains/{subDomainUid} Deleting a subdomain clears its reference from all projects, project templates, term bases, and translation memories. Project managers who did not create the subdomain need the clientDeleteOther access right (default off) to delete it. # Edit subdomain Source: https://developers.phrase.com/en/api/tms/latest/subdomain/edit-subdomain /openapi/phrase-tms-latest.json put /api2/v1/subDomains/{subDomainUid} Project managers can edit another user's subdomain only if they have the clientEditOther access right (default off). # Get subdomain Source: https://developers.phrase.com/en/api/tms/latest/subdomain/get-subdomain /openapi/phrase-tms-latest.json get /api2/v1/subDomains/{subDomainUid} Project managers who did not create the subdomain need the clientViewOther access right (default off) to view it. # List subdomains Source: https://developers.phrase.com/en/api/tms/latest/subdomain/list-subdomains /openapi/phrase-tms-latest.json get /api2/v1/subDomains Subdomain is used together with domain to further refine the content-type/category classification of projects, project templates, translation memories, and term bases. Linguists, submitters, and guests receive only subdomains from projects they are assigned to. # List supported languages Source: https://developers.phrase.com/en/api/tms/latest/supported-languages/list-supported-languages /openapi/phrase-tms-latest.json get /api2/v1/languages When the active parameter is omitted or false, all languages supported by the platform are returned. When active is true, the result is filtered to the locales currently enabled for the calling user's organization. # Browse term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/browse-term-base /openapi/phrase-tms-latest.json post /api2/v1/termBases/{termBaseUid}/browse # Clear term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/clear-term-base /openapi/phrase-tms-latest.json delete /api2/v1/termBases/{termBaseUid}/terms Deletes all terms # Create concept Source: https://developers.phrase.com/en/api/tms/latest/term-base/create-concept /openapi/phrase-tms-latest.json post /api2/v1/termBases/{termBaseUid}/concepts Creates an empty concept grouping with no terms. To add terms, use POST /api2/v1/termBases/{termBaseUid}/terms with conceptId pointing to this concept. # Create term Source: https://developers.phrase.com/en/api/tms/latest/term-base/create-term /openapi/phrase-tms-latest.json post /api2/v1/termBases/{termBaseUid}/terms Set conceptId to assign the term to an existing concept, otherwise a new concept will be created. Callable by ADMIN, PROJECT_MANAGER, and LINGUIST users assigned to the term base's project. A LINGUIST can always create a term with status New; creating a term with status Approved additionally requires the user's editAllTermsInTB right. This is distinct from the account-level rights gating the term base resource itself (see createTermBase/updateTermBase/deleteTermBase). # Create term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/create-term-base /openapi/phrase-tms-latest.json post /api2/v1/termBases Governs the term base resource itself (name, languages, ownership, whole-glossary deletion) via account-level term-base rights. This is distinct from the per-term content permissions on the terms/concepts endpoints below, which also allow LINGUIST users assigned to the project (see createTerm/updateTerm/deleteTerm). # Create term in job's term bases Source: https://developers.phrase.com/en/api/tms/latest/term-base/create-term-in-jobs-term-bases /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/termBases/createByJob Create new term in the write term base assigned to the job # Delete concept Source: https://developers.phrase.com/en/api/tms/latest/term-base/delete-concept /openapi/phrase-tms-latest.json delete /api2/v1/termBases/{termBaseUid}/concepts/{conceptId} Callable by ADMIN, PROJECT_MANAGER, and LINGUIST users assigned to the term base's project. This is distinct from the account-level rights gating the term base resource itself (see createTermBase/updateTermBase/deleteTermBase). There is no purge/restore option — the concept and all its terms cannot be recovered once deleted. # Delete concepts Source: https://developers.phrase.com/en/api/tms/latest/term-base/delete-concepts /openapi/phrase-tms-latest.json delete /api2/v1/termBases/{termBaseUid}/concepts Callable by ADMIN, PROJECT_MANAGER, and LINGUIST users assigned to the term base's project. This is distinct from the account-level rights gating the term base resource itself (see createTermBase/updateTermBase/deleteTermBase). There is no purge/restore option — the concepts and all their terms cannot be recovered once deleted. # Delete term Source: https://developers.phrase.com/en/api/tms/latest/term-base/delete-term /openapi/phrase-tms-latest.json delete /api2/v1/termBases/{termBaseUid}/terms/{termId} Callable by ADMIN, PROJECT_MANAGER, and LINGUIST users assigned to the term base's project. A LINGUIST can always delete a term with status New; deleting an already-Approved term additionally requires the user's editAllTermsInTB right. This is distinct from the account-level rights gating the term base resource itself (see createTermBase/updateTermBase/deleteTermBase). There is no purge/restore option — the term cannot be recovered once deleted. # Delete term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/delete-term-base /openapi/phrase-tms-latest.json delete /api2/v1/termBases/{termBaseUid} Governs the term base resource itself (name, languages, ownership, whole-glossary deletion) via account-level term-base rights. This is distinct from the per-term content permissions on the terms/concepts endpoints below, which also allow LINGUIST users assigned to the project (see createTerm/updateTerm/deleteTerm). # Edit term Source: https://developers.phrase.com/en/api/tms/latest/term-base/edit-term /openapi/phrase-tms-latest.json put /api2/v1/termBases/{termBaseUid}/terms/{termId} Callable by ADMIN, PROJECT_MANAGER, and LINGUIST users assigned to the term base's project. A LINGUIST can always edit a term with status New; editing/approving an already-Approved term additionally requires the user's editAllTermsInTB right. This is distinct from the account-level rights gating the term base resource itself (see createTermBase/updateTermBase/deleteTermBase). # Edit term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/edit-term-base /openapi/phrase-tms-latest.json put /api2/v1/termBases/{termBaseUid} It is possible to add new languages only. Governs the term base resource itself (name, languages, ownership, whole-glossary deletion) via account-level term-base rights. This is distinct from the per-term content permissions on the terms/concepts endpoints below, which also allow LINGUIST users assigned to the project (see createTerm/updateTerm/deleteTerm). # Export term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/export-term-base /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid}/export # Get concept Source: https://developers.phrase.com/en/api/tms/latest/term-base/get-concept /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid}/concepts/{conceptId} # Get term Source: https://developers.phrase.com/en/api/tms/latest/term-base/get-term /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid}/terms/{termId} # Get term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/get-term-base /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid} # Get term base metadata Source: https://developers.phrase.com/en/api/tms/latest/term-base/get-term-base-metadata /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid}/metadata # Get terms of concept Source: https://developers.phrase.com/en/api/tms/latest/term-base/get-terms-of-concept /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid}/concepts/{conceptId}/terms # Last import status Source: https://developers.phrase.com/en/api/tms/latest/term-base/last-import-status /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid}/lastBackgroundTask # List concepts Source: https://developers.phrase.com/en/api/tms/latest/term-base/list-concepts /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid}/concepts # List related projects Source: https://developers.phrase.com/en/api/tms/latest/term-base/list-related-projects /openapi/phrase-tms-latest.json get /api2/v1/termBases/{termBaseUid}/relatedProjects Reverse lookup of the projects a term base is attached to or assigned to. # List term bases Source: https://developers.phrase.com/en/api/tms/latest/term-base/list-term-bases /openapi/phrase-tms-latest.json get /api2/v1/termBases # Search job's term bases Source: https://developers.phrase.com/en/api/tms/latest/term-base/search-jobs-term-bases /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/jobs/{jobUid}/termBases/searchByJob Search all read term bases assigned to the job # Search term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/search-term-base /openapi/phrase-tms-latest.json post /api2/v1/termBases/{termBaseUid}/search # Search terms in text Source: https://developers.phrase.com/en/api/tms/latest/term-base/search-terms-in-text /openapi/phrase-tms-latest.json post /api2/v2/projects/{projectUid}/jobs/{jobUid}/termBases/searchInTextByJob Search in text in all read term bases assigned to the job # Update concept Source: https://developers.phrase.com/en/api/tms/latest/term-base/update-concept /openapi/phrase-tms-latest.json put /api2/v1/termBases/{termBaseUid}/concepts/{conceptId} # Upload term base Source: https://developers.phrase.com/en/api/tms/latest/term-base/upload-term-base /openapi/phrase-tms-latest.json post /api2/v2/termBases/{termBaseUid}/upload Terms can be imported from XLS/XLSX and TBX file formats into a term base. See Phrase Help Center # Add target language to translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/add-target-language-to-translation-memory /openapi/phrase-tms-latest.json post /api2/v1/transMemories/{transMemoryUid}/targetLanguages # Align translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/align-translation-memory /openapi/phrase-tms-latest.json post /api2/v2/transMemories/{transMemoryUid}/align Aligns files for a translation memory using its source locale. Submit either a sourceFile + targetFile pair, or a single archiveFile containing paired source and target files (mutually exclusive). Returns the aligned XLSX as an octet-stream, or 400 with a warning when the backend cannot align an archiveFile bundle. # Bulk delete segments Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/bulk-delete-segments /openapi/phrase-tms-latest.json post /api2/v2/transMemories/{transMemoryUid}/segments/bulkDelete When `lang` is omitted, both the source and all translations are removed for each segment. When `lang` is provided, only that translation is removed. This operation is permanent - deleted segments cannot be recovered. # Create translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/create-translation-memory /openapi/phrase-tms-latest.json post /api2/v1/transMemories Creates a new translation memory. At least one target language must be provided. Optional associations (client, domain, subDomain, businessUnit) are resolved by ID. Requires the caller to have the transMemoryCreate access right. # Delete all segments Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/delete-all-segments /openapi/phrase-tms-latest.json delete /api2/v2/transMemories/{transMemoryUid}/segments This call is **asynchronous**, use [this API](../async-request/get-asynchronous-request) to check the result. This operation is permanent - deleted segments cannot be recovered. # Delete both source and translation Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/delete-both-source-and-translation /openapi/phrase-tms-latest.json delete /api2/v1/transMemories/{transMemoryUid}/segments/{segmentId} Not recommended for bulk removal of segments. This operation is permanent - deleted segments cannot be recovered. # Delete segment of given language Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/delete-segment-of-given-language /openapi/phrase-tms-latest.json delete /api2/v1/transMemories/{transMemoryUid}/segments/{segmentId}/lang/{lang} Not recommended for bulk removal of segments. This operation is permanent - deleted segments cannot be recovered. # Delete translation memories (batch) Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/delete-translation-memories-batch /openapi/phrase-tms-latest.json delete /api2/v1/transMemories/bulk Deletes up to 100 translation memories in a single request. When purge=true on the request body all listed TMs are permanently erased. Each TM UID must be accessible to the caller; a missing or forbidden UID causes the entire request to fail. # Delete translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/delete-translation-memory /openapi/phrase-tms-latest.json delete /api2/v1/transMemories/{transMemoryUid} Deletes the specified translation memory. When purge=true the TM data is permanently erased; otherwise the TM is soft-deleted and can be recovered by an administrator. Requires internal role and DELETE permission on the TM. # Download cleaned TM Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/download-cleaned-tm /openapi/phrase-tms-latest.json get /api2/v1/transMemories/downloadCleaned/{asyncRequestId} Downloads the ZIP archive produced by extractCleaned. Returns 403 Forbidden when the extract-cleaned feature is not enabled for the organisation. The asyncRequest must be in a completed state. # Download export Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/download-export /openapi/phrase-tms-latest.json get /api2/v1/transMemories/downloadExport/{asyncRequestId} Downloads the TMX or XLSX file produced by exportByQueryAsync. The asyncRequest must be in a completed state before downloading. Use the fields parameter to select which columns to include when format=XLSX. # Edit segment Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/edit-segment /openapi/phrase-tms-latest.json put /api2/v1/transMemories/{transMemoryUid}/segments/{segmentId} # Edit translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/edit-translation-memory /openapi/phrase-tms-latest.json put /api2/v1/transMemories/{transMemoryUid} # Export translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/export-translation-memory /openapi/phrase-tms-latest.json post /api2/v2/transMemories/{transMemoryUid}/export Use [this API](../translation-memory/download-export) to download result. Requires Admin, Project Manager, or Guest role; not available to Linguist or Submitter roles. Linguist-role callers should use [List translation memory segments](../translation-memory/list-translation-memory-segments) instead. # Extract cleaned translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/extract-cleaned-translation-memory /openapi/phrase-tms-latest.json post /api2/v1/transMemories/extractCleaned Queues an asynchronous job that extracts cleaned TM content into a ZIP archive. Returns 403 Forbidden when the extract-cleaned feature is not enabled for the organisation. Poll the returned asyncRequest for completion, then download the result via downloadCleaned/{asyncRequestId}. # Get last task information Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/get-last-task-information /openapi/phrase-tms-latest.json get /api2/v1/transMemories/{transMemoryUid}/lastBackgroundTask # Get translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/get-translation-memory /openapi/phrase-tms-latest.json get /api2/v1/transMemories/{transMemoryUid} # Get translation memory metadata Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/get-translation-memory-metadata /openapi/phrase-tms-latest.json get /api2/v1/transMemories/{transMemoryUid}/metadata # Import translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/import-translation-memory /openapi/phrase-tms-latest.json post /api2/v2/transMemories/{transMemoryUid}/import Accepts TMX (.tmx), XLIFF (.xlf, .xliff), MXLIFF (.mxlf, .mxliff), and Excel (.xls, .xlsx). Format is detected from the filename extension. This call is **asynchronous**, use [this API](../async-request/get-asynchronous-request) to check the result. Requires the "Import into TMs created by other users" access right (transMemoryImportOther) unless the caller owns or created the TM. # Insert segment Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/insert-segment /openapi/phrase-tms-latest.json post /api2/v1/transMemories/{transMemoryUid}/segments # List related projects Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/list-related-projects /openapi/phrase-tms-latest.json get /api2/v1/transMemories/{transMemoryUid}/relatedProjects Reverse lookup of the projects a translation memory is attached to, used in, or assigned to. # List translation memories Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/list-translation-memories /openapi/phrase-tms-latest.json get /api2/v2/transMemories # List translation memory segments Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/list-translation-memory-segments /openapi/phrase-tms-latest.json post /api2/v2/transMemories/{transMemoryUid}/segments Synchronous, paginated JSON listing of translation memory segments. A blank or "*" query lists all segments. Available to Admin, Project Manager, Guest, and Linguist roles. Each segment's `tagMetadata` holds the actual content behind its inline tags (e.g. locked/non-translatable sub-text, original embedded markup) rather than plain text — see the `TagMetadata` model for details. # Search TM content Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/search-tm-content /openapi/phrase-tms-latest.json post /api2/v1/transMemories/{transMemoryUid}/searchContent **Overview** - Searches TM content within a single Translation Memory (TM), matching against source and/or target segment text, with optional metadata filters. **Interpreting found results** - Searching a TARGET locale → response contains the matching target TUV plus the source TUV for that TU. - Searching a SOURCE locale → response contains the full TU (matching source TUV and all target TUVs). One TU counts as a single found item, but the UI should render N `` pairs. **Query modes** - Exact query (plain text, no wildcard markers, regex disabled): if `sourceOperator|targetOperator=IS|IS_NOT` (exact mode) the whole field must (not) match exactly; if `CONTAINS|DOES_NOT_CONTAIN` (contains mode) the text may appear anywhere within the field. - Wildcard query (`sourceUseRegex|targetUseRegex=false`): uses `?` (single character) and `*` (multi-character) placeholders. `*` is only supported as a terminal suffix (end of word/token) — e.g. `trans*` matches `translation`/`transfer`; `tr?nslate` matches `translate`/`trenslate`. - Regex query (`sourceUseRegex|targetUseRegex=true`): `REGEXP` searches for substrings (not whole-word by default). Elasticsearch 8.14.3 / Lucene 9.10 supports `\w`, `\W`, `\d`, `\D`, `\s`, `\S`; word boundaries `\b`/`\B` are not supported. Prefer wildcard queries for word-based matching. **Metadata filters** - `filters` accepts multiple metadata filter criteria (projects, domain, subdomains, ...); AND logic is applied across them. **Defaults & limitations** - Whitespace is normalized; the wildcard processor can filter out Phrase tags. - Even wildcard results are post-filtered to enforce correct word order. - A single query is capped at 10,000 matches. If more than 10,000 segments match, only the first 10,000 are returned and `totalElements` will not exceed that cap. **Execution & performance notes** - `REGEXP` uses non-analyzed normalized fields; additional post-validation ensures fidelity to the original query text. - Matching TUVs are collected until `batchSize` is reached; only then are sibling TUVs from the same TU loaded. - For pagination (changing `index`), ES results are re-processed to keep `totalElements` accurate. # Search translation memory Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/search-translation-memory /openapi/phrase-tms-latest.json post /api2/v1/transMemories/{transMemoryUid}/exportByQueryAsync **Overview** Runs an asynchronous TMX export based on optional wildcard/phrase queries and optional metadata filters. The job streams filtered translation units into TMX via the downstream `/export_tmx_by_query` endpoint. Use `downloadExport/{asyncRequestId}` to fetch the finished file. **Flow** 1. Caller posts `ExportByQueryDto`. 2. Service queues backend export (job metadata marks it asynchronous). 3. Response contains `asyncRequest` + `asyncExport` descriptors so you can poll or receive callbacks. **`queries` + `queryLangs` — intersection (AND), optional** - `queries` and `queryLangs` are optional and must align 1-to-1 when provided. - Each pair applies a search expression to its locale. Multiple pairs are **AND-intersected**: a TU must satisfy every pair (it must have a TUV in each pair's locale that matches the query). - Query values: unquoted text = contains; quoted text = phrase; `*`/`?` wildcards (max 5/10); no regex/boolean operators. - `"*"` means match-all **but the locale filter still applies** — the TU must have a TUV in that locale (real AND constraint). - `""` (empty string) or null means **no constraint** — that pair is ignored entirely and does not participate in the AND. Sending all-empty queries is the same as omitting `queries` altogether. - When `queries` is omitted or all entries are empty/null, the export falls through to OR-over-`exportTargetLangs` (see below). **`exportTargetLangs` — disjunction (OR), optional** - Controls which target TUVs are written to the TMX. A TU is kept if it has at least one TUV matching any of the listed locales. - `null` / omitted — no locale filter; the **whole TU** is exported with **all** its target TUVs. - Present but empty (or all entries invalid) — produces an **empty TMX** (not the same as null). - To export TUs updated in any of N languages (OR semantics), put the N locales in `exportTargetLangs` and leave `queries`/`queryLangs` empty — do NOT put them in `queries`/`queryLangs` (that would AND them). **Examples** Export TUs that have an es or de TUV (OR — recommended for multi-language sync): `{ "exportTargetLangs": ["es_es","de_de"] }` Export TUs that have BOTH es AND de TUVs (AND): `{ "queries": ["*","*"], "queryLangs": ["es_es","de_de"], "exportTargetLangs": ["es_es","de_de"] }` **Filtering** - Timestamp bounds (`createdAtMin/Max`, `modifiedAtMin/Max`) and author filters (`createdBy`, `modifiedBy`) narrow the TU set before export. **Output & limits** - Output is always TMX, streamed in chunks; filenames follow `dto.filename` when provided, otherwise backend defaults. - Requests with excessive locales or wildcard limit violations reject with `400`. - If no matches remain after filtering, the job still produces an empty TMX. **Callbacks & polling** - Provide `callbackUrl` to receive completion notification from the async mediator; otherwise poll `asyncRequest` via standard async APIs and download through `/downloadExport/{asyncRequestId}` when ready. # Search translation memory for segment by job Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/search-translation-memory-for-segment-by-job /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/transMemories/searchSegment Returns at most maxSegments records with score >= scoreThreshold and at most maxSubsegments records which are subsegment, i.e. the source text is substring of the query text. # Search translation memory (sync) Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/search-translation-memory-sync /openapi/phrase-tms-latest.json post /api2/v1/transMemories/{transMemoryUid}/search **Overview** - Searches a single translation memory using the primary TM scoring pipeline. The endpoint always returns up to 15 `SearchTMResponseDto` entries ordered by score. **Modes** - Standard segment search (default): normalize text, leverage penalties, thresholds, tag metadata, and context. This is the behavior when `phraseQuery=true`(default). The service calls the downstream `/search` endpoint with `wildcard=true` to allow combined exact/wildcard candidates in one pass. - Legacy phrase-only mode: set `phraseQuery=false` to disable the wildcard branch (`wildcard=false`, `exactIfQuotes=false`, `combinedExact=false`). Use when you need strict normalized matches without wildcard processing. **Request parameters** - `query` (required): search text. If `trimQuery=true` (default) leading/trailing whitespace is removed before sending to TM service. - `sourceLang` (required) and optional `targetLangs`: locales are normalized. When `targetLangs` is omitted the backend queries all TM targets. - `previousSegment` / `nextSegment`: optional context strings; when provided, the backend raises 101% matches that align with the surrounding segments. - `tagMetadata`: serialized inline tags; improves scoring and avoids dropping tag pairs. - `trimQuery`: default `true`. Set to `false` to preserve leading/trailing spaces (rare). - `phraseQuery`: default `true`. Controls whether wildcard/phrase helpers are enabled (see “Modes”). **Scoring & ordering** - Backend computes `grossScore` (raw similarity) and `score` (penalty-adjusted). 101% matches retain their priority even after penalties. - Ordering priority (per downstream service): `score DESC`, `grossScore DESC`, context match priority DESC, segment key ASC, TM priority ASC, timestamp DESC, TU id DESC. - Numeric replacements or uppercase normalization are not performed here (`replaceFigures=false`, `modifyTransText=false` in this controller). **Limits & behavior** - Returns maximum 15 matches; there is no `offset` or `totalFoundCount`. - Threshold is fixed to `0`, so all results above penalties are returned until limit. - Multiple target locales per TM are not supported, mirroring backend validation. - Logical operators (AND/OR/NOT) and wildcard expressions in `query` are interpreted only when `phraseQuery=true` enables the wildcard path. **Context & caching notes** - Downstream service may consult its 60-second cache for identical search inputs (including context and penalties). Freshly imported matches might appear with a short delay if cached results are reused. - If previous/next segments are omitted the search still runs, but 101% context boosts cannot trigger. **Error handling** - Invalid locales, blank `query`, or an inaccessible TM ID return `400`/`403`. - Backend may throw when multiple target locales are submitted for a single TM; the controller surfaces that error unchanged. # Wildcard search Source: https://developers.phrase.com/en/api/tms/latest/translation-memory/wildcard-search /openapi/phrase-tms-latest.json post /api2/v1/transMemories/{transMemoryUid}/wildCardSearch **Overview** - Searches a single translation memory via Elasticsearch wildcard queries and returns up to `count` matches. **Query semantics** - `query` supports `*` (multi-character, single-token) and `?` (single-character) wildcards. Queries map directly to ES `query_string`, so ordering is flexible and Boolean operators from user input are ignored. - If `query` is omitted or blank, the service falls back to `*`, which matches any source segment. **Query examples** Imagine having segment: `Good morning` Query: - `good morn*` → matches `Good morning`. - `morn* good` → matches `Good morning` (word order ignored in contains mode). - `goof morn*` → also matches `Good morning` because any matching token is sufficient. - `*` → matches any TM segment. - `"good morn*"` → treated literally; returns no results unless the segment actually contains the quotes. - ``Good morning`` (no quotes) → matches `Good morning`. **Request limits** - `count` must be between `1` and `50` (default `15`). - `offset` must be ≥ `0` (default `0`). - `sourceLang` must be a valid locale; `targetLangs` is optional (defaults to the TM target locales when omitted). **Scoring and ordering** - Backend returns both `grossScore` (raw) and `score` (penalty-adjusted, never negative). - Ordering priority: `score DESC`, `grossScore DESC`, TM order ASC, modified or created timestamp DESC, source TUV ID ASC. **Target handling** - Hits without targets in the requested locales are filtered out. - Multiple requested target locales produce multiple ordered target records per hit. **Validation & errors** - Invalid locales, `count`/`offset` outside allowed bounds, or missing TM access rights yield `400`/`403`. - Because no total size is returned, clients should consider using `offset + count` to detect pagination end (empty page ⇒ done). # Human translate (Gengo or Unbabel) Source: https://developers.phrase.com/en/api/tms/latest/translation/human-translate-gengo-or-unbabel /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/humanTranslate # Pre-translate job Source: https://developers.phrase.com/en/api/tms/latest/translation/pre-translate-job /openapi/phrase-tms-latest.json post /api2/v3/projects/{projectUid}/jobs/preTranslate Starts pre-translation for one or more jobs. Returns HTTP 202 immediately; translation runs asynchronously. **Precondition:** Every job must have `importStatus.status == "OK"` (check via [Get job](../job/get-job)). Submitting a job before import completes returns `400 JOB_NOT_READY`. **Precondition:** When `useProjectPreTranslateSettings` is `false`, `preTranslateSettings` must be provided. Omitting it returns `400 PRE_TRANSLATE_SETTINGS_REQUIRED`. **Async tracking:** The response body contains an `asyncRequest` object. Poll [Get asynchronous request](../async-request/get-asynchronous-request) (action: `PRE_TRANSLATE`) to track completion. `asyncResponse` is `null` while pending. **Alternative:** Set `preTranslate: true` in the `Memsource` header when calling [Create job](../job/create-job) to trigger pre-translation automatically after import, removing the need to poll `importStatus.status` first. **MT engine:** `useMachineTranslation` has no engine-selection field of its own — pre-translation uses whichever MT engine is currently assigned to the project. See [Get project machine translate settings](../project/get-project-machine-translate-settings) / [Assign machine translate engine to project](../project/assign-machine-translate-engine-to-project) to check or change the effective engine. **Workflow step targeting:** Apply pre-translation only to the lowest active workflow step. Triggering pre-translation on a higher workflow step after the project has already been pre-translated breaks real-time propagation from lower steps. # Translate using machine translation Source: https://developers.phrase.com/en/api/tms/latest/translation/translate-using-machine-translation /openapi/phrase-tms-latest.json post /api2/v1/projects/{projectUid}/jobs/{jobUid}/translations/translateWithMachineTranslation Translates source texts using the job's configured machine translation settings. The MT origin is determined from request headers. Requires job machine translation access; project-level machine translation access may also be checked. # List last login dates Source: https://developers.phrase.com/en/api/tms/latest/user/list-last-login-dates /openapi/phrase-tms-latest.json get /api2/v1/users/lastLogins # List users Source: https://developers.phrase.com/en/api/tms/latest/user/list-users /openapi/phrase-tms-latest.json get /api2/v1/users # Edit my profile Source: https://developers.phrase.com/en/api/tms/latest/user-profile/edit-my-profile /openapi/phrase-tms-latest.json put /api2/v1/userProfile If the caller's identity is managed by an external identity provider (SSO/SCIM/SAML), the readonly flag in the response is true and firstName/lastName/email changes are silently ignored - only the subscribed flag is applied (when marketing consent is not hidden). Check readonly beforehand to avoid relying on a no-op edit. # Get my profile Source: https://developers.phrase.com/en/api/tms/latest/user-profile/get-my-profile /openapi/phrase-tms-latest.json get /api2/v1/userProfile # Create user Source: https://developers.phrase.com/en/api/tms/latest/user/create-user /openapi/phrase-tms-latest.json post /api2/v3/users When sendInvitation=true, an invitation email is sent to the user and the password field is ignored. When sendInvitation=false (default), a welcome email is sent and the password field is used if provided. # Delete user Source: https://developers.phrase.com/en/api/tms/latest/user/delete-user /openapi/phrase-tms-latest.json delete /api2/v1/users/{userUid} # Disable two-factor authentication Source: https://developers.phrase.com/en/api/tms/latest/user/disable-two-factor-authentication /openapi/phrase-tms-latest.json post /api2/v3/users/{userUid}/disableTwoFactorAuth # Edit user Source: https://developers.phrase.com/en/api/tms/latest/user/edit-user /openapi/phrase-tms-latest.json put /api2/v3/users/{userUid} # Get user Source: https://developers.phrase.com/en/api/tms/latest/user/get-user /openapi/phrase-tms-latest.json get /api2/v3/users/{userUid} # List assigned projects Source: https://developers.phrase.com/en/api/tms/latest/user/list-assigned-projects /openapi/phrase-tms-latest.json get /api2/v1/users/{userUid}/projects List projects in which the user is assigned to at least one job matching the criteria. ADMIN and PROJECT_MANAGER callers receive a richer ProjectAdminReference response; all other roles receive a ProjectLinguistReference response. # List assigned target languages Source: https://developers.phrase.com/en/api/tms/latest/user/list-assigned-target-languages /openapi/phrase-tms-latest.json get /api2/v1/users/{userUid}/targetLangs # List assigned workflow steps Source: https://developers.phrase.com/en/api/tms/latest/user/list-assigned-workflow-steps /openapi/phrase-tms-latest.json get /api2/v1/users/{userUid}/workflowSteps # List jobs assigned to user across all projects Source: https://developers.phrase.com/en/api/tms/latest/user/list-jobs-assigned-to-user-across-all-projects /openapi/phrase-tms-latest.json get /api2/v1/users/{userUid}/jobs Returns jobs assigned to the given user across all projects and all workflow steps - unlike GET /api2/v2/projects/{projectUid}/jobs, this endpoint has no default `workflowLevel` restriction. Use `dueInHours=-1` to filter for jobs due in the past. This does not exclude jobs by status - `DELIVERED`, `COMPLETED`, `CANCELLED`, `DECLINED` and `REJECTED` jobs are still matched. Combine with `status` (excluding `DELIVERED`, `COMPLETED`, `CANCELLED`, `DECLINED` and `REJECTED`) to match the product's "overdue" definition. Use `dateCreatedFrom`/`dateCreatedTo` to filter jobs by their creation date range. Both are optional and, when omitted, no creation date filtering is applied. # Login statistics Source: https://developers.phrase.com/en/api/tms/latest/user/login-statistics /openapi/phrase-tms-latest.json get /api2/v1/users/{userUid}/loginStatistics Returns login activity for the specified user. ADMIN users can view any user's activity; non-admin users can only view their own. # Restore user Source: https://developers.phrase.com/en/api/tms/latest/user/restore-user /openapi/phrase-tms-latest.json post /api2/v1/users/{userUid}/undelete Restores a previously deleted user. Requires ADMIN role. The user must belong to the same organization and must not be a bot account. # Send login information Source: https://developers.phrase.com/en/api/tms/latest/user/send-login-information /openapi/phrase-tms-latest.json post /api2/v1/users/{userUid}/emailLoginInformation # Update password Source: https://developers.phrase.com/en/api/tms/latest/user/update-password /openapi/phrase-tms-latest.json post /api2/v1/users/{userUid}/updatePassword Can be used by the user to update their own password or by ADMIN to update password of user without joined account * Password length must be between 8 and 255 * Password must not be same as the username # Create vendor Source: https://developers.phrase.com/en/api/tms/latest/vendor/create-vendor /openapi/phrase-tms-latest.json post /api2/v1/vendors # Delete vendors (batch) Source: https://developers.phrase.com/en/api/tms/latest/vendor/delete-vendors-batch /openapi/phrase-tms-latest.json delete /api2/v1/vendors # Get vendor Source: https://developers.phrase.com/en/api/tms/latest/vendor/get-vendor /openapi/phrase-tms-latest.json get /api2/v1/vendors/{vendorUid} # List vendors Source: https://developers.phrase.com/en/api/tms/latest/vendor/list-vendors /openapi/phrase-tms-latest.json get /api2/v1/vendors Returns only approved vendors. # Create webhook Source: https://developers.phrase.com/en/api/tms/latest/webhook/create-webhook /openapi/phrase-tms-latest.json post /api2/v2/webhooks # Delete webhook Source: https://developers.phrase.com/en/api/tms/latest/webhook/delete-webhook /openapi/phrase-tms-latest.json delete /api2/v2/webhooks/{webHookUid} # Edit webhook Source: https://developers.phrase.com/en/api/tms/latest/webhook/edit-webhook /openapi/phrase-tms-latest.json put /api2/v2/webhooks/{webHookUid} # Get webhook Source: https://developers.phrase.com/en/api/tms/latest/webhook/get-webhook /openapi/phrase-tms-latest.json get /api2/v2/webhooks/{webHookUid} # Get webhook body previews Source: https://developers.phrase.com/en/api/tms/latest/webhook/get-webhook-body-previews /openapi/phrase-tms-latest.json get /api2/v2/webhooks/previews # Lists webhook calls Source: https://developers.phrase.com/en/api/tms/latest/webhook/lists-webhook-calls /openapi/phrase-tms-latest.json get /api2/v1/webhooksCalls # Lists webhooks Source: https://developers.phrase.com/en/api/tms/latest/webhook/lists-webhooks /openapi/phrase-tms-latest.json get /api2/v2/webhooks # Replay last webhook calls Source: https://developers.phrase.com/en/api/tms/latest/webhook/replay-last-webhook-calls /openapi/phrase-tms-latest.json post /api2/v1/webhooksCalls/replay/latest Replays specified number of last Webhook calls from oldest to the newest one # Replay webhook calls Source: https://developers.phrase.com/en/api/tms/latest/webhook/replay-webhook-calls /openapi/phrase-tms-latest.json post /api2/v1/webhooksCalls/replay Replays given list of Webhook Calls in specified order in the request # Send test webhook Source: https://developers.phrase.com/en/api/tms/latest/webhook/send-test-webhook /openapi/phrase-tms-latest.json post /api2/v2/webhooks/{webhookUid}/test Returns 400 if the webhook does not include the specified event. # Download workflow changes report Source: https://developers.phrase.com/en/api/tms/latest/workflow-changes/download-workflow-changes-report /openapi/phrase-tms-latest.json post /api2/v2/jobs/workflowChanges Returns an HTML report of translation differences between workflow steps for the specified jobs. All jobs must belong to the same project. The project must have at least two workflow steps configured. Required role: Administrator or Project Manager. # Create workflow step Source: https://developers.phrase.com/en/api/tms/latest/workflow-step/create-workflow-step /openapi/phrase-tms-latest.json post /api2/v1/workflowSteps Requires ADMIN or PROJECT_MANAGER role with the setup-server access right. Abbreviation must be unique within the organization. When order is omitted, the step is appended to the end of the organization's workflow step list (highest existing order + 10, or 0 if none exist). On success, the new step is automatically added to all existing price lists and discount schemes. Returns 403 if the organization plan does not support workflow steps or if LQA is not enabled for the organization when lqaEnabled is true. # Delete workflow step Source: https://developers.phrase.com/en/api/tms/latest/workflow-step/delete-workflow-step /openapi/phrase-tms-latest.json delete /api2/v1/workflowSteps/{workflowStepUid} Requires ADMIN or PROJECT_MANAGER role with the setup-server access right. Soft-deletes the step and removes all associated price list entries. Returns 403 if the organization plan does not support workflow steps. # Edit workflow step Source: https://developers.phrase.com/en/api/tms/latest/workflow-step/edit-workflow-step /openapi/phrase-tms-latest.json put /api2/v1/workflowSteps/{workflowStepUid} Requires ADMIN or PROJECT_MANAGER role with the setup-server access right. All fields are optional; omitted or null fields retain their existing values. Abbreviation must be unique within the organization. Returns 403 if the organization plan does not support workflow steps or if LQA is not enabled for the organization when lqaEnabled is true. # Get workflow step Source: https://developers.phrase.com/en/api/tms/latest/workflow-step/get-workflow-step /openapi/phrase-tms-latest.json get /api2/v1/workflowSteps/{workflowStepUid} Requires ADMIN or PROJECT_MANAGER role with the setup-server access right. Returns 403 if the organization plan does not support workflow steps. # List workflow steps Source: https://developers.phrase.com/en/api/tms/latest/workflow-step/list-workflow-steps /openapi/phrase-tms-latest.json get /api2/v1/workflowSteps Accessible to ADMIN, PROJECT_MANAGER, GUEST, and LINGUIST roles. Returns 403 if the organization plan does not support workflow steps. # Get XML assistant profiles for organization Source: https://developers.phrase.com/en/api/tms/latest/xml-assistant/get-xml-assistant-profiles-for-organization /openapi/phrase-tms-latest.json get /api2/v1/xmlAssistantProfiles # Authentication Source: https://developers.phrase.com/en/api/connectors/authentication ## Phrase Platform API tokens The Phrase Connectors API uses API key authentication. Generate a Phrase Platform JWT token as described [here](/en/api/platform/authentication) ### Using Your API Key Include your API key in the `Authentication` header with every API request: ```bash theme={null} curl -X GET "https://eu.phrase.com/connectors/connectors/v1" \ -H "Authentication: Bearer GENERATED_JWT_TOKEN" ``` # Convert stored raw Braze content to XLIFF asynchronously Source: https://developers.phrase.com/en/api/connectors/braze/convert-stored-raw-braze-content-to-xliff-asynchronously /openapi/phrase-connectors.json post /braze_multilang/v1/async/convert-to-xliff Convert raw Braze content already in Phrase file storage to XLIFF 2.0, without re-downloading from Braze. Each entry in `rawFiles` references a stored file (`storageId`) plus the metadata the connector needs to segment correctly. Use this when you have a snapshot from `download-raw-file` and want to defer the conversion step (e.g. to apply custom pre-processing first). **Async variant.** Returns `{ requestId, webHookUrl }` immediately; the XLIFF (or its `storageId`) is POSTed to `X-Webhook`. # Convert stored raw Braze content to XLIFF synchronously Source: https://developers.phrase.com/en/api/connectors/braze/convert-stored-raw-braze-content-to-xliff-synchronously /openapi/phrase-connectors.json post /braze_multilang/v1/sync/convert-to-xliff Convert raw Braze content already in Phrase file storage to XLIFF 2.0, without re-downloading from Braze. Each entry in `rawFiles` references a stored file (`storageId`) plus the metadata the connector needs to segment correctly. Use this when you have a snapshot from `download-raw-file` and want to defer the conversion step (e.g. to apply custom pre-processing first). # Convert stored XLIFF back to raw Braze content asynchronously Source: https://developers.phrase.com/en/api/connectors/braze/convert-stored-xliff-back-to-raw-braze-content-asynchronously /openapi/phrase-connectors.json post /braze_multilang/v1/async/convert-to-raw Convert a translated XLIFF (referenced by `storageId`) back into Braze's raw content format without writing it to Braze. The result is stored in Phrase file storage and returned as a `storageId` you can then push with `upload-raw-file`. Use this when the upload step is decoupled from the conversion step (e.g. for a preview/review gate). **Async variant.** Returns `{ requestId, webHookUrl }` immediately; the raw file (or its `storageId`) is POSTed to `X-Webhook`. # Convert stored XLIFF back to raw Braze content synchronously Source: https://developers.phrase.com/en/api/connectors/braze/convert-stored-xliff-back-to-raw-braze-content-synchronously /openapi/phrase-connectors.json post /braze_multilang/v1/sync/convert-to-raw Convert a translated XLIFF (referenced by `storageId`) back into Braze's raw content format without writing it to Braze. The result is stored in Phrase file storage and returned as a `storageId` you can then push with `upload-raw-file`. Use this when the upload step is decoupled from the conversion step (e.g. for a preview/review gate). # Download Braze multilingual content as XLIFF asynchronously Source: https://developers.phrase.com/en/api/connectors/braze/download-braze-multilingual-content-as-xliff-asynchronously /openapi/phrase-connectors.json post /braze_multilang/v1/async/download-xliff-file Download Braze multilingual content as XLIFF 2.0, ready for translation. The connector applies its segmentation and serialization rules, including locale fallbacks across the source and target Braze locale codes. Pair with `upload-xliff-file` once translated. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The XLIFF is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Download Braze multilingual content as XLIFF synchronously Source: https://developers.phrase.com/en/api/connectors/braze/download-braze-multilingual-content-as-xliff-synchronously /openapi/phrase-connectors.json post /braze_multilang/v1/sync/download-xliff-file Download Braze multilingual content as XLIFF 2.0, ready for translation. The connector applies its segmentation and serialization rules, including locale fallbacks across the source and target Braze locale codes. Pair with `upload-xliff-file` once translated. # Download raw Braze multilingual content asynchronously Source: https://developers.phrase.com/en/api/connectors/braze/download-raw-braze-multilingual-content-asynchronously /openapi/phrase-connectors.json post /braze_multilang/v1/async/download-raw-file Download raw multilingual content from Braze without any connector-side conversion. The returned payload is Braze's native JSON representation of the content blocks / campaigns selected by `path` and `configuration`. Use this when you want the original, untranslated content (e.g. to build a custom preview, snapshot a Braze workspace, or feed an analytics pipeline). For translation-ready content, use `download-xliff-file` instead. **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small selections and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large selections. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for tiny payloads, but holds the file in memory. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The actual download result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Download raw Braze multilingual content synchronously Source: https://developers.phrase.com/en/api/connectors/braze/download-raw-braze-multilingual-content-synchronously /openapi/phrase-connectors.json post /braze_multilang/v1/sync/download-raw-file Download raw multilingual content from Braze without any connector-side conversion. The returned payload is Braze's native JSON representation of the content blocks / campaigns selected by `path` and `configuration`. Use this when you want the original, untranslated content (e.g. to build a custom preview, snapshot a Braze workspace, or feed an analytics pipeline). For translation-ready content, use `download-xliff-file` instead. **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small selections and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large selections. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for tiny payloads, but holds the file in memory. # List Braze multilingual content asynchronously Source: https://developers.phrase.com/en/api/connectors/braze/list-braze-multilingual-content-asynchronously /openapi/phrase-connectors.json post /braze_multilang/v1/async/list-files List Braze multilingual content reachable from `path` under the supplied `configuration`. Use this for project setup, change detection, or to drive a UI picker. The response is a list of `remoteResources`, each carrying a `path` you can feed back into download / convert endpoints. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The listing is POSTed to the URL supplied in `X-Webhook`. # List Braze multilingual content synchronously Source: https://developers.phrase.com/en/api/connectors/braze/list-braze-multilingual-content-synchronously /openapi/phrase-connectors.json post /braze_multilang/v1/sync/list-files List Braze multilingual content reachable from `path` under the supplied `configuration`. Use this for project setup, change detection, or to drive a UI picker. The response is a list of `remoteResources`, each carrying a `path` you can feed back into download / convert endpoints. # Upload raw Braze multilingual content asynchronously Source: https://developers.phrase.com/en/api/connectors/braze/upload-raw-braze-multilingual-content-asynchronously /openapi/phrase-connectors.json post /braze_multilang/v1/async/upload-raw-file Upload raw multilingual content back to Braze. The request body must reference an already-stored file by `storageId` — upload the file to Phrase file storage first. Use this when you have non-XLIFF content (e.g. a manually edited content-block export). For translated XLIFF, use `upload-xliff-file`. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The actual upload result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Upload raw Braze multilingual content synchronously Source: https://developers.phrase.com/en/api/connectors/braze/upload-raw-braze-multilingual-content-synchronously /openapi/phrase-connectors.json post /braze_multilang/v1/sync/upload-raw-file Upload raw multilingual content back to Braze. The request body must reference an already-stored file by `storageId` — upload the file to Phrase file storage first. Use this when you have non-XLIFF content (e.g. a manually edited content-block export). For translated XLIFF, use `upload-xliff-file`. # Upload translated XLIFF asynchronously Source: https://developers.phrase.com/en/api/connectors/braze/upload-translated-xliff-asynchronously /openapi/phrase-connectors.json post /braze_multilang/v1/async/upload-xliff-file Upload translated XLIFF back to Braze. The connector parses the XLIFF, maps target-language segments back onto the original Braze content, and writes them to the target locale in the configured workspace. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The upload result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Upload translated XLIFF synchronously Source: https://developers.phrase.com/en/api/connectors/braze/upload-translated-xliff-synchronously /openapi/phrase-connectors.json post /braze_multilang/v1/sync/upload-xliff-file Upload translated XLIFF back to Braze. The connector parses the XLIFF, maps target-language segments back onto the original Braze content, and writes them to the target locale in the configured workspace. # List available connectors Source: https://developers.phrase.com/en/api/connectors/connectors/list-available-connectors /openapi/phrase-connectors.json get /connectors/v1 Returns all Bifrost-compatible connectors you have configured. # Convert an XLIFF file from the connector to a raw file used by Contentful asynchronously Source: https://developers.phrase.com/en/api/connectors/contentful/convert-an-xliff-file-from-the-connector-to-a-raw-file-used-by-contentful-asynchronously /openapi/phrase-connectors.json post /contentful2/v1/async/convert-to-raw Convert a translated XLIFF (referenced by `storageId`) back into Contentful's raw entry format without writing it to Contentful. The result is stored in Phrase file storage and returned as a `storageId` you can then push with `upload-raw-file`. Use this when the upload step is decoupled from the conversion step (e.g. for a preview/review gate). **Async variant.** Returns `{ requestId, webHookUrl }` immediately; the raw file (or its `storageId`) is POSTed to `X-Webhook`. # Convert an XLIFF file from the connector to a raw file used by Contentful synchronously Source: https://developers.phrase.com/en/api/connectors/contentful/convert-an-xliff-file-from-the-connector-to-a-raw-file-used-by-contentful-synchronously /openapi/phrase-connectors.json post /contentful2/v1/sync/convert-to-raw Convert a translated XLIFF (referenced by `storageId`) back into Contentful's raw entry format without writing it to Contentful. The result is stored in Phrase file storage and returned as a `storageId` you can then push with `upload-raw-file`. Use this when the upload step is decoupled from the conversion step (e.g. for a preview/review gate). # Convert raw content from Contentful to XLIFF asynchronously Source: https://developers.phrase.com/en/api/connectors/contentful/convert-raw-content-from-contentful-to-xliff-asynchronously /openapi/phrase-connectors.json post /contentful2/v1/async/convert-to-xliff Convert raw Contentful content already in Phrase file storage to XLIFF 2.0, without re-downloading from Contentful. Each entry in `rawFiles` references a stored file (`storageId`) plus the metadata the connector needs to segment correctly. Use this when you have a snapshot from `download-raw-file` and want to defer the conversion step (e.g. to apply custom pre-processing first). **Async variant.** Returns `{ requestId, webHookUrl }` immediately; the XLIFF (or its `storageId`) is POSTed to `X-Webhook`. # Convert raw content from Contentful to XLIFF synchronously Source: https://developers.phrase.com/en/api/connectors/contentful/convert-raw-content-from-contentful-to-xliff-synchronously /openapi/phrase-connectors.json post /contentful2/v1/sync/convert-to-xliff Convert raw Contentful content already in Phrase file storage to XLIFF 2.0, without re-downloading from Contentful. Each entry in `rawFiles` references a stored file (`storageId`) plus the metadata the connector needs to segment correctly. Use this when you have a snapshot from `download-raw-file` and want to defer the conversion step (e.g. to apply custom pre-processing first). # Download raw content asynchronously Source: https://developers.phrase.com/en/api/connectors/contentful/download-raw-content-asynchronously /openapi/phrase-connectors.json post /contentful2/v1/async/download-raw-file Download raw entry content from Contentful without any connector-side conversion. The returned payload is Contentful's native JSON representation of the entries selected by `path` and `configuration`. Use this when you want the original, untranslated content (e.g. to build a custom preview, snapshot a space, or feed an analytics pipeline). For translation-ready content, use `download-xliff-file` instead. **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small spaces and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large spaces. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for tiny payloads, but holds the file in memory. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The actual download result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Download raw content synchronously Source: https://developers.phrase.com/en/api/connectors/contentful/download-raw-content-synchronously /openapi/phrase-connectors.json post /contentful2/v1/sync/download-raw-file Download raw entry content from Contentful without any connector-side conversion. The returned payload is Contentful's native JSON representation of the entries selected by `path` and `configuration`. Use this when you want the original, untranslated content (e.g. to build a custom preview, snapshot a space, or feed an analytics pipeline). For translation-ready content, use `download-xliff-file` instead. **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small spaces and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large spaces. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for tiny payloads, but holds the file in memory. # Download xliff content asynchronously Source: https://developers.phrase.com/en/api/connectors/contentful/download-xliff-content-asynchronously /openapi/phrase-connectors.json post /contentful2/v1/async/download-xliff-file Download Contentful entries as XLIFF 2.0, ready for translation. The connector applies its segmentation and serialization rules (rich-text handling, reference inlining, locale fallbacks). Pair with `upload-xliff-file` once translated. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The XLIFF is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Download xliff content synchronously Source: https://developers.phrase.com/en/api/connectors/contentful/download-xliff-content-synchronously /openapi/phrase-connectors.json post /contentful2/v1/sync/download-xliff-file Download Contentful entries as XLIFF 2.0, ready for translation. The connector applies its segmentation and serialization rules (rich-text handling, reference inlining, locale fallbacks). Pair with `upload-xliff-file` once translated. # List content asynchronously Source: https://developers.phrase.com/en/api/connectors/contentful/list-content-asynchronously /openapi/phrase-connectors.json post /contentful2/v1/async/list-files List Contentful entries (and optionally referenced assets) reachable from `path` under the supplied `configuration`. Use this for project setup, change detection, or to drive a UI picker. The response is a list of `remoteResources`, each carrying a `path` you can feed back into download / convert endpoints. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The listing is POSTed to the URL supplied in `X-Webhook`. # List content synchronously Source: https://developers.phrase.com/en/api/connectors/contentful/list-content-synchronously /openapi/phrase-connectors.json post /contentful2/v1/sync/list-files List Contentful entries (and optionally referenced assets) reachable from `path` under the supplied `configuration`. Use this for project setup, change detection, or to drive a UI picker. The response is a list of `remoteResources`, each carrying a `path` you can feed back into download / convert endpoints. # Upload raw content asynchronously Source: https://developers.phrase.com/en/api/connectors/contentful/upload-raw-content-asynchronously /openapi/phrase-connectors.json post /contentful2/v1/async/upload-raw-file Upload raw entry content back to Contentful for a given target locale. The request body must reference an already-stored file by `storageId` — upload the file to Phrase file storage first. Use this when you have non-XLIFF content (e.g. a manually edited entry export). For translated XLIFF, use `upload-xliff-file`. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The actual upload result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Upload raw content synchronously Source: https://developers.phrase.com/en/api/connectors/contentful/upload-raw-content-synchronously /openapi/phrase-connectors.json post /contentful2/v1/sync/upload-raw-file Upload raw entry content back to Contentful for a given target locale. The request body must reference an already-stored file by `storageId` — upload the file to Phrase file storage first. Use this when you have non-XLIFF content (e.g. a manually edited entry export). For translated XLIFF, use `upload-xliff-file`. # Upload xliff content asynchronously Source: https://developers.phrase.com/en/api/connectors/contentful/upload-xliff-content-asynchronously /openapi/phrase-connectors.json post /contentful2/v1/async/upload-xliff-file Upload translated XLIFF back to Contentful. The connector parses the XLIFF, maps target-language segments back onto the original entries, and writes them to the target locale in the configured space. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The upload result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Upload xliff content synchronously Source: https://developers.phrase.com/en/api/connectors/contentful/upload-xliff-content-synchronously /openapi/phrase-connectors.json post /contentful2/v1/sync/upload-xliff-file Upload translated XLIFF back to Contentful. The connector parses the XLIFF, maps target-language segments back onto the original entries, and writes them to the target locale in the configured space. # Download file from file storage synchronously Source: https://developers.phrase.com/en/api/connectors/files/download-file-from-file-storage-synchronously /openapi/phrase-connectors.json get /files/v1/download-file/{uid} Download file synchronously from the file storage. # Upload file to file storage asynchronously Source: https://developers.phrase.com/en/api/connectors/files/upload-file-to-file-storage-asynchronously /openapi/phrase-connectors.json post /files/v1/async/upload-file Upload file asynchronously to the file storage. The file is saved and can be retrieved by sending a GET request to this endpoint. The returned ID can be used as a parameter for uploading files to third party systems or for file conversion. The file will be deleted after 1 day. # Upload file to file storage synchronously Source: https://developers.phrase.com/en/api/connectors/files/upload-file-to-file-storage-synchronously /openapi/phrase-connectors.json post /files/v1/sync/upload-file Upload file synchronously to the file storage. The file is saved and can be retrieved by sending a GET request to this endpoint. The returned ID can be used as a parameter for uploading files to third party systems or for file conversion. The file will be deleted after 1 day. # Batch upload raw files asynchronously — single commit via Git Blob/Tree API Source: https://developers.phrase.com/en/api/connectors/github/batch-upload-raw-files-asynchronously-—-single-commit-via-git-blobtree-api /openapi/phrase-connectors.json post /github2/v1/async/upload-batch-raw-files # Batch upload raw files synchronously — single commit via Git Blob/Tree API Source: https://developers.phrase.com/en/api/connectors/github/batch-upload-raw-files-synchronously-—-single-commit-via-git-blobtree-api /openapi/phrase-connectors.json post /github2/v1/sync/upload-batch-raw-files # Download raw content asynchronously Source: https://developers.phrase.com/en/api/connectors/github/download-raw-content-asynchronously /openapi/phrase-connectors.json post /github2/v1/async/download-raw-file # Download raw content synchronously Source: https://developers.phrase.com/en/api/connectors/github/download-raw-content-synchronously /openapi/phrase-connectors.json post /github2/v1/sync/download-raw-file # List content asynchronously Source: https://developers.phrase.com/en/api/connectors/github/list-content-asynchronously /openapi/phrase-connectors.json post /github2/v1/async/list-files # List content synchronously Source: https://developers.phrase.com/en/api/connectors/github/list-content-synchronously /openapi/phrase-connectors.json post /github2/v1/sync/list-files # Upload raw content asynchronously Source: https://developers.phrase.com/en/api/connectors/github/upload-raw-content-asynchronously /openapi/phrase-connectors.json post /github2/v1/async/upload-raw-file # Upload raw content synchronously Source: https://developers.phrase.com/en/api/connectors/github/upload-raw-content-synchronously /openapi/phrase-connectors.json post /github2/v1/sync/upload-raw-file # Download raw content from Google Drive asynchronously Source: https://developers.phrase.com/en/api/connectors/google-drive/download-raw-content-from-google-drive-asynchronously /openapi/phrase-connectors.json post /google-drive/v1/async/download-raw-file Download a raw binary file from Google Drive without any connector-side conversion. The returned payload is the original file bytes as stored in Drive (Docs/Sheets/Slides are exported as their native binary equivalents when applicable). Use this when you need the source artefact intact (e.g. PDF, DOCX, image, video). Google Drive is a binary-file connector — there is no XLIFF or raw-to-XLIFF conversion endpoint. **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small files and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large files. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for small payloads; the stream may be proxied directly from Drive with upstream `Content-Type`, `Content-Disposition`, and `Content-Length` headers preserved when available. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The download result is POSTed to the URL supplied in `X-Webhook`. # Download raw content from Google Drive synchronously Source: https://developers.phrase.com/en/api/connectors/google-drive/download-raw-content-from-google-drive-synchronously /openapi/phrase-connectors.json post /google-drive/v1/sync/download-raw-file Download a raw binary file from Google Drive without any connector-side conversion. The returned payload is the original file bytes as stored in Drive (Docs/Sheets/Slides are exported as their native binary equivalents when applicable). Use this when you need the source artefact intact (e.g. PDF, DOCX, image, video). Google Drive is a binary-file connector — there is no XLIFF or raw-to-XLIFF conversion endpoint. **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small files and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large files. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for small payloads; the stream may be proxied directly from Drive with upstream `Content-Type`, `Content-Disposition`, and `Content-Length` headers preserved when available. **Response shape (this endpoint)** is controlled by the `X-ResponseType` request header: - `ID`: returns JSON with a `storageId` referencing file storage (`application/json`) - `OBJECT`: returns a binary stream (`application/octet-stream`). Two variants: - Streaming: proxied stream from the connector; status and headers (`Content-Type`, `Content-Disposition`, `Content-Length`) may come from upstream when present. - File storage: Bifrost downloads from storage (single file or zip of multiple files) and returns `application/octet-stream` with `Content-Disposition: attachment; filename=""`. # List Google Drive content asynchronously Source: https://developers.phrase.com/en/api/connectors/google-drive/list-google-drive-content-asynchronously /openapi/phrase-connectors.json post /google-drive/v1/async/list-files List folders and files reachable from `path` in Google Drive. Use this for project setup, change detection, or to drive a UI picker. The `path.pathType` selects the scope: - `ROOT` — list available top-level spaces ("My Drive" and "Shared drives") - `SHARED_DRIVES_ROOT` — list all shared drives accessible to the credentials - `FOLDER` — list children of the given folder The response is a list of `remoteResources`. Each entry carries a resolved `path` you can feed back into `download-raw-file` or `upload-raw-file`. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The listing is POSTed to the URL supplied in `X-Webhook`. # List Google Drive content synchronously Source: https://developers.phrase.com/en/api/connectors/google-drive/list-google-drive-content-synchronously /openapi/phrase-connectors.json post /google-drive/v1/sync/list-files List folders and files reachable from `path` in Google Drive. Use this for project setup, change detection, or to drive a UI picker. The `path.pathType` selects the scope: - `ROOT` — list available top-level spaces ("My Drive" and "Shared drives") - `SHARED_DRIVES_ROOT` — list all shared drives accessible to the credentials - `FOLDER` — list children of the given folder The response is a list of `remoteResources`. Each entry carries a resolved `path` you can feed back into `download-raw-file` or `upload-raw-file`. # Upload raw content to Google Drive asynchronously Source: https://developers.phrase.com/en/api/connectors/google-drive/upload-raw-content-to-google-drive-asynchronously /openapi/phrase-connectors.json post /google-drive/v1/async/upload-raw-file Upload a raw binary file to Google Drive. Two delivery modes are supported via `X-Upload-Mode`: - **STORAGE** (default) — the request body references a file already in Phrase file storage by `storageId`. The connector pulls the bytes itself and writes them to the target Drive location. Returns the standard `UploadResponse` envelope. - **STREAM** — initialize a two-phase streaming upload (recommended for large files). `storageId` must be omitted. The response carries `{ uploadUrl, streamToken, expiresAt, maxBytes }`. The caller then PUTs the raw bytes to `uploadUrl` with the matching `X-Stream-Token` header — see `PUT /google-drive/v1/sync/upload-raw-file/stream/{streamId}`. For async uploads, only STORAGE mode is supported and `storageId` is required. **Async variant.** Only `X-Upload-Mode: STORAGE` is supported — `storageId` is required. The endpoint returns immediately with `{ requestId, webHookUrl }` and the actual upload result is POSTed to the URL supplied in `X-Webhook`. # Upload raw content to Google Drive synchronously Source: https://developers.phrase.com/en/api/connectors/google-drive/upload-raw-content-to-google-drive-synchronously /openapi/phrase-connectors.json post /google-drive/v1/sync/upload-raw-file Upload a raw binary file to Google Drive. Two delivery modes are supported via `X-Upload-Mode`: - **STORAGE** (default) — the request body references a file already in Phrase file storage by `storageId`. The connector pulls the bytes itself and writes them to the target Drive location. Returns the standard `UploadResponse` envelope. - **STREAM** — initialize a two-phase streaming upload (recommended for large files). `storageId` must be omitted. The response carries `{ uploadUrl, streamToken, expiresAt, maxBytes }`. The caller then PUTs the raw bytes to `uploadUrl` with the matching `X-Stream-Token` header — see `PUT /google-drive/v1/sync/upload-raw-file/stream/{streamId}`. For async uploads, only STORAGE mode is supported and `storageId` is required. # Upload raw file bytes to Google Drive (streaming, phase 2) Source: https://developers.phrase.com/en/api/connectors/google-drive/upload-raw-file-bytes-to-google-drive-streaming-phase-2 /openapi/phrase-connectors.json put /google-drive/v1/sync/upload-raw-file/stream/{streamId} Phase 2 of the streaming upload flow. The caller PUTs raw bytes to this endpoint after initializing a streaming upload via `POST /google-drive/v1/sync/upload-raw-file` with `X-Upload-Mode: STREAM`. The `{streamId}` path segment and `X-Stream-Token` header value both come from the phase-1 response (`uploadUrl` already embeds the `streamId`; `X-Stream-Token` is the `streamToken` field). The token is single-use and expires at `expiresAt`. The body must be the raw file bytes; total size must not exceed the `maxBytes` returned by phase 1. On success, the endpoint returns `204 No Content`. # Introduction Source: https://developers.phrase.com/en/api/connectors/introduction ## Phrase Connectors API Reference A tool for building custom flows using Phrase Integrations. Easily connect localization processes with external systems and extend built-in integrations with your own functionality. # Convert stored raw Optimizely content to XLIFF asynchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/convert-stored-raw-optimizely-content-to-xliff-asynchronously /openapi/phrase-connectors.json post /optimizely/v1/async/convert-to-xliff Convert raw Optimizely content already in Phrase file storage to XLIFF 2.0, without re-downloading from Optimizely. Each entry in `rawFiles` references a stored file (`storageId`) plus the metadata the connector needs to segment correctly. Use this when you have a snapshot from `download-raw-file` and want to defer the conversion step (e.g. to apply custom pre-processing first). **Async variant.** Returns `{ requestId, webHookUrl }` immediately; the XLIFF (or its `storageId`) is POSTed to `X-Webhook`. # Convert stored raw Optimizely content to XLIFF synchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/convert-stored-raw-optimizely-content-to-xliff-synchronously /openapi/phrase-connectors.json post /optimizely/v1/sync/convert-to-xliff Convert raw Optimizely content already in Phrase file storage to XLIFF 2.0, without re-downloading from Optimizely. Each entry in `rawFiles` references a stored file (`storageId`) plus the metadata the connector needs to segment correctly. Use this when you have a snapshot from `download-raw-file` and want to defer the conversion step (e.g. to apply custom pre-processing first). # Convert stored XLIFF back to raw Optimizely content asynchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/convert-stored-xliff-back-to-raw-optimizely-content-asynchronously /openapi/phrase-connectors.json post /optimizely/v1/async/convert-to-raw Convert a translated XLIFF (referenced by `storageId`) back into Optimizely's raw content format without writing it to Optimizely. The result is stored in Phrase file storage and returned as a `storageId` you can then push with `upload-raw-file`. Use this when the upload step is decoupled from the conversion step (e.g. for a preview/review gate). **Async variant.** Returns `{ requestId, webHookUrl }` immediately; the raw file (or its `storageId`) is POSTed to `X-Webhook`. # Convert stored XLIFF back to raw Optimizely content synchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/convert-stored-xliff-back-to-raw-optimizely-content-synchronously /openapi/phrase-connectors.json post /optimizely/v1/sync/convert-to-raw Convert a translated XLIFF (referenced by `storageId`) back into Optimizely's raw content format without writing it to Optimizely. The result is stored in Phrase file storage and returned as a `storageId` you can then push with `upload-raw-file`. Use this when the upload step is decoupled from the conversion step (e.g. for a preview/review gate). # Download Optimizely content as XLIFF asynchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/download-optimizely-content-as-xliff-asynchronously /openapi/phrase-connectors.json post /optimizely/v1/async/download-xliff-file Download Optimizely content as XLIFF 2.0, ready for translation. The connector applies its segmentation and serialization rules to produce a translation-ready file targeting the requested locale pair. Pair with `upload-xliff-file` once translated. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The XLIFF is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Download Optimizely content as XLIFF synchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/download-optimizely-content-as-xliff-synchronously /openapi/phrase-connectors.json post /optimizely/v1/sync/download-xliff-file Download Optimizely content as XLIFF 2.0, ready for translation. The connector applies its segmentation and serialization rules to produce a translation-ready file targeting the requested locale pair. Pair with `upload-xliff-file` once translated. # Download raw Optimizely content asynchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/download-raw-optimizely-content-asynchronously /openapi/phrase-connectors.json post /optimizely/v1/async/download-raw-file Download raw content from Optimizely without any connector-side conversion. The returned payload is Optimizely's native representation of the content items selected by `path` and `configuration`. Use this when you want the original, untranslated content (e.g. to build a custom preview, snapshot a project, or feed an analytics pipeline). For translation-ready content, use `download-xliff-file` instead. **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small payloads and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large payloads. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for tiny payloads, but holds the file in memory. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The actual download result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Download raw Optimizely content synchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/download-raw-optimizely-content-synchronously /openapi/phrase-connectors.json post /optimizely/v1/sync/download-raw-file Download raw content from Optimizely without any connector-side conversion. The returned payload is Optimizely's native representation of the content items selected by `path` and `configuration`. Use this when you want the original, untranslated content (e.g. to build a custom preview, snapshot a project, or feed an analytics pipeline). For translation-ready content, use `download-xliff-file` instead. **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small payloads and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large payloads. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for tiny payloads, but holds the file in memory. # List Optimizely content items asynchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/list-optimizely-content-items-asynchronously /openapi/phrase-connectors.json post /optimizely/v1/async/list-files List Optimizely content items reachable from `path` under the supplied `configuration`. Use this for project setup, change detection, or to drive a UI picker. The response is a list of `remoteResources`, each carrying a `path` you can feed back into download / convert endpoints. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The listing is POSTed to the URL supplied in `X-Webhook`. # List Optimizely content items synchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/list-optimizely-content-items-synchronously /openapi/phrase-connectors.json post /optimizely/v1/sync/list-files List Optimizely content items reachable from `path` under the supplied `configuration`. Use this for project setup, change detection, or to drive a UI picker. The response is a list of `remoteResources`, each carrying a `path` you can feed back into download / convert endpoints. # Upload raw Optimizely content asynchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/upload-raw-optimizely-content-asynchronously /openapi/phrase-connectors.json post /optimizely/v1/async/upload-raw-file Upload raw content back to Optimizely for a given target locale. The request body must reference an already-stored file by `storageId` — upload the file to Phrase file storage first. Use this when you have non-XLIFF content (e.g. a manually edited content export). For translated XLIFF, use `upload-xliff-file`. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The actual upload result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Upload raw Optimizely content synchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/upload-raw-optimizely-content-synchronously /openapi/phrase-connectors.json post /optimizely/v1/sync/upload-raw-file Upload raw content back to Optimizely for a given target locale. The request body must reference an already-stored file by `storageId` — upload the file to Phrase file storage first. Use this when you have non-XLIFF content (e.g. a manually edited content export). For translated XLIFF, use `upload-xliff-file`. # Upload translated XLIFF asynchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/upload-translated-xliff-asynchronously /openapi/phrase-connectors.json post /optimizely/v1/async/upload-xliff-file Upload translated XLIFF back to Optimizely. The connector parses the XLIFF, maps target-language segments back onto the original content items, and writes them to the target locale in the configured project. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The upload result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Upload translated XLIFF synchronously Source: https://developers.phrase.com/en/api/connectors/optimizely/upload-translated-xliff-synchronously /openapi/phrase-connectors.json post /optimizely/v1/sync/upload-xliff-file Upload translated XLIFF back to Optimizely. The connector parses the XLIFF, maps target-language segments back onto the original content items, and writes them to the target locale in the configured project. # Upload raw Tridion content synchronously Source: https://developers.phrase.com/en/api/connectors/tridion-docs/upload-raw-tridion-content-synchronously /openapi/phrase-connectors.json post /tridion/v1/sync/upload-raw-file Upload raw content back to SDL Tridion for a given target locale. The request body must reference an already-stored file by `storageId` — upload the file to Phrase file storage first. Use this when you have non-XLIFF content (e.g. a manually edited item export). # Authentication Source: https://developers.phrase.com/en/api/control-hub/authentication The Content Groups API uses Phrase Platform authentication. Generate an API token for **Phrase Content Groups** in the [Phrase Platform Settings](https://eu.phrase.com/idm-ui/settings/access-tokens), then exchange it for a JWT as described in the [Platform Authentication guide](/en/api/platform/authentication). Include the JWT in the `Authorization` header on every request: ```bash theme={null} curl -X GET "https://eu.phrase.com/control-hub/api/v1/public/groups" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` JWTs expire after a few hours. Re-issue a new JWT from your long-lived API token when the previous one expires; do not store JWTs at rest. # Create a content group Source: https://developers.phrase.com/en/api/control-hub/groups/create-a-content-group /openapi/phrase-control-hub.json post /api/v1/public/groups # Delete a content group Source: https://developers.phrase.com/en/api/control-hub/groups/delete-a-content-group /openapi/phrase-control-hub.json delete /api/v1/public/groups/{groupId} Deletes the content group and all its object references. # Get a single content group Source: https://developers.phrase.com/en/api/control-hub/groups/get-a-single-content-group /openapi/phrase-control-hub.json get /api/v1/public/groups/{groupId} # List content groups for the caller's organization Source: https://developers.phrase.com/en/api/control-hub/groups/list-content-groups-for-the-callers-organization /openapi/phrase-control-hub.json get /api/v1/public/groups # List references linked to the content group Source: https://developers.phrase.com/en/api/control-hub/groups/list-references-linked-to-the-content-group /openapi/phrase-control-hub.json get /api/v1/public/groups/{groupId}/references # Update a content group Source: https://developers.phrase.com/en/api/control-hub/groups/update-a-content-group /openapi/phrase-control-hub.json put /api/v1/public/groups/{groupId} # Introduction Source: https://developers.phrase.com/en/api/control-hub/introduction ## Phrase Content Groups API Reference 1.0.20 Content Groups are organization-scoped named containers that connect platform objects across the Phrase product suite. They act as the single matching principle for the translation and quality workflow: a TMS project, its Style Guides, Style Rules, and AI quality checks all resolve through a shared Content Group. ### Key Features * **Full group management** — create, retrieve, update, and delete Content Groups for your organization * **Reference listing** — retrieve the platform objects linked to a group, with optional filtering by `objectType` * **Typed object references** — supported types are `TMS_PROJECT`, `TMS_PROJECT_TEMPLATE`, `PLATFORM_STYLE_GUIDE`, `PLATFORM_STYLE_RULE`, and `PLATFORM_QA_CHECK` ### The SYSTEM content group Every organization has exactly one platform-managed **SYSTEM** content group, named "All Groups," representing "applies to all content groups." It's created automatically — you never create it yourself — and appears in `listGroups`/reference-listing results like any other group, distinguished by `groupType: SYSTEM` on the `Group` object (all other groups have `groupType: USER`). * **Immutable** — `PUT`/`DELETE` on a SYSTEM group returns `403 Forbidden`. Its name and description can never change; only the objects linked to it can. * **`SYSTEM` alias** — use the literal string `SYSTEM` in place of a real group id when getting a group or listing its references (`GET /groups/{groupId}`, `GET /groups/{groupId}/references`). It is not accepted on `PUT`/`DELETE /groups/{groupId}`. * **`includeSystem` filter** — `listGroups` and a group's `listGroupReferences` both accept `includeSystem` (default `true`) to include/exclude the SYSTEM group and its references from results. * **Restricted object types** — `PLATFORM_STYLE_GUIDE`, `TMS_PROJECT`, and `TMS_PROJECT_TEMPLATE` references are never linked to the SYSTEM group; only `PLATFORM_QA_CHECK` and `PLATFORM_STYLE_RULE` references can appear under it. You won't see the restricted types in `listGroupReferences` results for the SYSTEM group. ### How Content Groups fit into the platform Content Groups are the coordination layer across Phrase products. Once a TMS project is linked to a Content Group: * The project's Style Guide and Style Rules are resolved from the group * Quality Evaluation draws its checks from the `(Content Group, locale)` pair * AI capabilities receive a Content Profile derived from the group's rules ### Base URL | Region | Base URL | | ------ | ----------------------------------- | | EU | `https://eu.phrase.com/control-hub` | | US | `https://us.phrase.com/control-hub` | ### Quick Start 1. **Exchange your API token** for a JWT via the [Authentication guide](/en/api/control-hub/authentication) 2. **Create a Content Group** for your organization 3. **Use the group ID** when configuring TMS projects or Style Guides in other Phrase products ```bash theme={null} curl -X POST "https://eu.phrase.com/control-hub/api/v1/public/groups" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{"name": "Marketing", "description": "Brand voice and campaign copy"}' ``` Browse the full operation set, request and response schemas, and per-endpoint examples in the **API Documentation** section of the left navigation. # Login Source: https://developers.phrase.com/en/api/language-ai/authentication/login /openapi/phrase-language-ai.json post /v1/auth/login DEPRECATED: Use as a fallback method only - Phrase Platform API tokens should be the preferred way. Returns information about the user with the token to be used in the Authorization header and its expiration date. # Action result Source: https://developers.phrase.com/en/api/language-ai/file-translations/action-result /openapi/phrase-language-ai.json get /v1/fileTranslations/{uid}/{actionType}/{language} Use the Accept header with either `application/octet-stream` to get the file or use `application/json` to get the quality estimation. # File processing metadata Source: https://developers.phrase.com/en/api/language-ai/file-translations/file-processing-metadata /openapi/phrase-language-ai.json get /v1/fileTranslations/{uid} Allows the fetching of metadata from the processing file. The completed file can be downloaded using the [File download](/en/api/language-ai/file-translations/action-result) endpoint. # File translations Source: https://developers.phrase.com/en/api/language-ai/file-translations/file-translations /openapi/phrase-language-ai.json post /v1/fileTranslations Creates a new file translations request based on multipart/form-data. The translation state can be fetched utilizing a returned UID in the response and a [Metadata](/en/api/language-ai/file-translations/file-processing-metadata) endpoint. It is also possible to download the translated file using the [Get file](/en/api/language-ai/file-translations/action-result) endpoint once the translation is complete (`action.status == OK`). # Introduction Source: https://developers.phrase.com/en/api/language-ai/introduction Learn how to use the Phrase Language AI API to translate content automatically using the best available machine translation engine for your language pair. ## Phrase Language AI API Reference 1.0.0 The Phrase Language AI API lets you translate content programmatically by automatically selecting the best available machine translation (MT) engine for each request. The selection is based on language pair, content type, and historical quality signals — you do not need to manage engine routing yourself. ### When to use this API Use the Language AI API when you want to integrate MT into your own pipeline or application without building engine-selection logic. If you are already using the Phrase TMS API for project and job management, the Language AI API can be used independently for on-demand translation. ### Limits and constraints * Requests are subject to per-account rate limits. Exceeding the limit returns a `429 Too Many Requests` response. * Maximum input length per request is documented on each endpoint. * Supported language pairs vary by underlying engine; unsupported pairs return a `422 Unprocessable Entity` response. # List Language AI Profiles Source: https://developers.phrase.com/en/api/language-ai/list-language-ai-profiles/list-language-ai-profiles /openapi/phrase-language-ai.json get /v1/translationProfiles List available Language AI profiles for the user. # Text translations Source: https://developers.phrase.com/en/api/language-ai/text-translations/text-translations /openapi/phrase-language-ai.json post /v1/textTranslations Translates the text content utilizing Phrase Language AI capabilities. Can identify the source language, if not provided, and translate the text to the target language. If language identification is requested, system needs to have at least 50 characters. # Text translations v2 Source: https://developers.phrase.com/en/api/language-ai/text-translations/text-translations-v2 /openapi/phrase-language-ai.json post /v2/textTranslations Translates the text content utilizing Phrase Language AI capabilities. Can identify the source language, if not provided, and translate the text to the target language. If language identification is requested, system needs to have at least 50 characters. # Authentication Source: https://developers.phrase.com/en/api/studio/authentication ## Phrase Platform API tokens The Phrase Studio API uses API key authentication. Generate a Phrase Platform JWT token as described [here](/en/api/platform/authentication) ### Using Your API Key Include your API key in the `X-API-Key` header with every API request: ```bash theme={null} curl -X GET "https://api.studio.us.phrase.com/v1/projects" \ -H "X-API-Key: YOUR_API_KEY" ``` ### Common Authentication Errors | Status Code | Description | | ---------------- | ------------------------------------------------------------------ | | 401 Unauthorized | Invalid or missing API key | | 403 Forbidden | API key is valid but doesn't have access to the requested resource | # Get Glossaries Source: https://developers.phrase.com/en/api/studio/glossaries/get-glossaries /openapi/phrase-studio.json get /v1/glossaries Retrieve available glossaries for the authenticated account. Items have newline character between them. # Get Insights Source: https://developers.phrase.com/en/api/studio/insights/get-insights /openapi/phrase-studio.json get /v1/insights Retrieve all insights available to the authenticated account. Insights are named collections of AI-powered prompts that analyze conversation transcripts and meeting recordings; each one groups related prompts (items) under a category such as `Earnings Call` or `Company Presentation`. The response includes both **shared** insights (`accountId` is null) and **account-specific** insights visible only to the owning account. # Introduction Source: https://developers.phrase.com/en/api/studio/introduction ## Phrase Studio API Reference 1.0.0 The Phrase Studio API enables you to programmatically create projects and retrieve transcription, translation, and dubbing results. This API allows you to integrate audio and video processing capabilities powered by AI into your applications. ### Key Features * **Project Management**: Create and manage transcription/translation/dubbing projects * **Multi-language Support**: Process content in over 100 languages * **Flexible Outputs**: Get results in multiple formats (SRT, VTT, MP3) * **Advanced Features**: Support for glossaries, pronunciations, insights, and safe communications * **Direct Upload & URL Import**: Upload files directly or import from external URLs ### Base URLs The Studio API is available in multiple environments: * **Production US**: `https://api.studio.us.phrase.com` * **Production EU**: `https://api.studio.eu.phrase.com` # Create Project Source: https://developers.phrase.com/en/api/studio/projects/create-project /openapi/phrase-studio.json post /v1/projects Creates an empty project and redirects the client to the upload service to upload files. After upload completion, the service will finalize the project automatically. Direct file uploads are more robust and recommended over providing fileUrls. Upload behavior and limits: - 10-minute inactivity timeout per upload stream. - If the client connection drops, the upload is aborted and cannot resume; retry from the start. - Multi-hour uploads are supported as long as data keeps flowing and the connection stays open. # Delete Project Source: https://developers.phrase.com/en/api/studio/projects/delete-project /openapi/phrase-studio.json delete /v1/projects/{id} Delete a specific project and all its associated recordings and data # Get Project Details Source: https://developers.phrase.com/en/api/studio/projects/get-project-details /openapi/phrase-studio.json get /v1/projects/{id} Retrieve detailed information about a specific project # List Projects Source: https://developers.phrase.com/en/api/studio/projects/list-projects /openapi/phrase-studio.json get /v1/projects Retrieve a list of projects for the authenticated account. # Update Project Settings Source: https://developers.phrase.com/en/api/studio/projects/update-project-settings /openapi/phrase-studio.json patch /v1/projects/{id} Update an existing project's AI model preferences, TTS provider, translation memory / MT profile assignment, and sharing visibility. The endpoint is partial: only fields present in the body are written, so a single field can be changed without resending the rest. Authorization is restricted to the project owner and other accounts in the same organization. # Get Pronunciations Source: https://developers.phrase.com/en/api/studio/pronunciations/get-pronunciations /openapi/phrase-studio.json get /v1/pronunciations Retrieve available pronunciations for the authenticated account # Get Recording Output Source: https://developers.phrase.com/en/api/studio/recordings/get-recording-output /openapi/phrase-studio.json get /v1/recordings/{recordingId} Retrieve transcription, translation or dubbing outputs using a single query-driven endpoint. # Get Recording Status Source: https://developers.phrase.com/en/api/studio/recordings/get-recording-status /openapi/phrase-studio.json get /v1/recordings/{recordingId}/status Retrieve the processing status of a recording. This endpoint supports three modes: 1. **Overall Status** (`summary=true`): Returns a high-level status string indicating the recording's overall state (PENDING, IN_PROGRESS, COMPLETED, or FAILED). 2. **All Languages Breakdown** (no params): Returns completion status for each processing step (transcription, translation, dubbing, summary) grouped by language code. Only completed steps are included in the response. 3. **Single Language Breakdown** (`language=`): Returns completion status for processing steps of a specific language. Only completed steps are included in the response. # Get Safe Communications Source: https://developers.phrase.com/en/api/studio/safe-communications/get-safe-communications /openapi/phrase-studio.json get /v1/safe-communications Retrieve available safe communications for the authenticated account # Get Subtitle Profiles Source: https://developers.phrase.com/en/api/studio/subtitle-profiles/get-subtitle-profiles /openapi/phrase-studio.json get /v1/subtitle-profiles Retrieve available subtitle profiles for the authenticated account # Get Subtitle Source: https://developers.phrase.com/en/api/studio/subtitles/get-subtitle /openapi/phrase-studio.json get /v1/projects/{projectId}/recordings/{recordingId}/subtitles Retrieve the structured subtitle segments of a recording's language track in JSON form (with word-level timings). The response shape mirrors the PUT request body — use this before `PUT` to fetch the current segments, edit the `words` array of the segment(s) you want to change (word-level text and timings are the source of truth; editing `text` alone has no effect), and send the full array back. The `source` and `dubbing` query flags pick which track to read: source transcription, target translation, or dubbing. ## Language scoping The `language` value must match the requested task type for the recording: * When `source=true` and `dubbing=false` (transcription), `language` must equal the recording source language. * When `source=false` and `dubbing=false` (translation), `language` must be one of the recording translation languages. * When `source=false` and `dubbing=true` (dubbing), `language` must be one of the recording translation languages. * `source=true` and `dubbing=true` together is invalid. Mismatched combinations return `400` with a descriptive message rather than reaching the underlying file lookup. # Update Subtitle Source: https://developers.phrase.com/en/api/studio/subtitles/update-subtitle /openapi/phrase-studio.json put /v1/projects/{projectId}/recordings/{recordingId}/subtitles Replace the subtitle segments of a recording's language track. The request body must contain **every** segment in the final state — the endpoint performs a bulk replace, not a partial patch. Any segment you omit is removed from the track. Use this to push subtitle edits made externally (for example, by AI editing tools) back into Studio. ## `words` is the source of truth — never send empty `words` Each segment's `words` array (word-level text and timings) is authoritative. Subtitle rendering **and** dubbing text-to-speech are generated from `words`; the segment-level `text` field is only a human-readable mirror and is **ignored** when rendering subtitles or synthesizing speech. A segment whose `words` array is empty is treated as having no content: it is **silently dropped the next time the track is read**, and for dubbing nothing is synthesized for it. This is the most common cause of a track that “comes back empty” after an update. Never submit `"words": []` unless you intend to remove that segment's content. To change what a segment says — for example, shortening a dubbing line — rewrite its `words` array, not just `text`. Mirror the change in `text` for readability, but the `words` entries are what actually change the rendered subtitle and the generated audio. ## Recommended workflow 1. `GET` the track to fetch the current segments with their word-level timings. 2. Edit the `words` array of the segment(s) you want to change (and mirror the new text in `text`). Leave every other segment untouched. 3. `PUT` the **full** segment array back. For a dubbing redub, list the changed segment ids in `segmentsToRedub` and keep `enqueueTtsUpdate=true` so their audio is regenerated from the new `words`. To edit text without triggering re-synthesis, set `enqueueTtsUpdate` to `false` — but still send the full `words` array for every segment. ## Language scoping The `language` value must match the requested task type for the recording: * When `source=true` and `dubbing=false` (transcription), `language` must equal the recording source language. * When `source=false` and `dubbing=false` (translation), `language` must be one of the recording translation languages. * When `source=false` and `dubbing=true` (dubbing), `language` must be one of the recording translation languages. * `source=true` and `dubbing=true` together is invalid. Mismatched combinations return `400` with a descriptive message rather than reaching the underlying file lookup. # Download raw Tridion content asynchronously Source: https://developers.phrase.com/en/api/connectors/tridion-docs/download-raw-tridion-content-asynchronously /openapi/phrase-connectors.json post /tridion/v1/async/download-raw-file Download raw content from SDL Tridion without any connector-side conversion. The returned payload is the native item content (typically XML) for the items selected by `path` and `configuration`. Use this when you want the original, untranslated content (e.g. to build a custom preview, snapshot a folder, or feed an analytics pipeline). **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small selections and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large selections. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for tiny payloads, but holds the file in memory. **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The actual download result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Download raw Tridion content synchronously Source: https://developers.phrase.com/en/api/connectors/tridion-docs/download-raw-tridion-content-synchronously /openapi/phrase-connectors.json post /tridion/v1/sync/download-raw-file Download raw content from SDL Tridion without any connector-side conversion. The returned payload is the native item content (typically XML) for the items selected by `path` and `configuration`. Use this when you want the original, untranslated content (e.g. to build a custom preview, snapshot a folder, or feed an analytics pipeline). **Choosing sync vs async** - `/sync/download-raw-file` blocks until the connector finishes. Use for small selections and interactive callers. Subject to gateway timeouts (~60 s). - `/async/download-raw-file` returns immediately with a `requestId` and posts the result to the URL in `X-Webhook` when ready. Required for large selections. **Response shape (sync only)** is controlled by `X-ResponseType`: - `ID` (default) — JSON `{ "storageId": "..." }`. The caller fetches the content from Phrase file storage later. Recommended for any non-trivial payload. - `OBJECT` — raw `application/octet-stream`. Faster for tiny payloads, but holds the file in memory. # List Tridion items asynchronously Source: https://developers.phrase.com/en/api/connectors/tridion-docs/list-tridion-items-asynchronously /openapi/phrase-connectors.json post /tridion/v1/async/list-files List Tridion items reachable from `path` under the supplied `configuration`. Use this for project setup, change detection, or to drive a UI picker. The response is a list of `remoteResources`, each carrying a `path` you can feed back into download endpoints. **Async variant.** Returns immediately with `{ requestId, webHookUrl }`. The listing is POSTed to the URL supplied in `X-Webhook`. # List Tridion items synchronously Source: https://developers.phrase.com/en/api/connectors/tridion-docs/list-tridion-items-synchronously /openapi/phrase-connectors.json post /tridion/v1/sync/list-files List Tridion items reachable from `path` under the supplied `configuration`. Use this for project setup, change detection, or to drive a UI picker. The response is a list of `remoteResources`, each carrying a `path` you can feed back into download endpoints. # Upload raw Tridion content asynchronously Source: https://developers.phrase.com/en/api/connectors/tridion-docs/upload-raw-tridion-content-asynchronously /openapi/phrase-connectors.json post /tridion/v1/async/upload-raw-file Upload raw content back to SDL Tridion for a given target locale. The request body must reference an already-stored file by `storageId` — upload the file to Phrase file storage first. Use this when you have non-XLIFF content (e.g. a manually edited item export). **Async variant.** This endpoint returns immediately with `{ requestId, webHookUrl }`. The actual upload result is POSTed to the URL supplied in `X-Webhook`. `X-Webhook` is required. # Get analytics Source: https://developers.phrase.com/en/api/quality-evaluator/latest/analytics/get-analytics /openapi/phrase-quality-evaluator-latest.json get /v1/analytics Returns aggregated daily evaluation rollup data for the caller's organization. Filtered by optional quality profile and date range. # Authentication Source: https://developers.phrase.com/en/api/quality-evaluator/latest/authentication The Quality Evaluator API uses Phrase Platform authentication. Generate an API token for **Quality Evaluator** in the [Phrase Platform Settings](https://eu.phrase.com/idm-ui/settings/access-tokens), then exchange it for a JWT as described in the [Platform Authentication guide](/en/api/platform/authentication). Include the JWT in the `Authorization` header with every request: ```bash theme={null} curl -X GET "https://eu.phrase.com/quality-evaluator/v3/qualityProfiles/cg-abc123" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` ### Required roles Most endpoints only require an authenticated caller. Analytics is restricted further: | Access level | Endpoints | | --------------------------- | -------------------------------- | | Any authenticated user | Quality Profile by Content Group | | **ADMIN** or **OWNER** role | Evaluate segments, Analytics | Requests to restricted endpoints made by users without the required role will receive a `403 Forbidden` response. # Evaluate segments Source: https://developers.phrase.com/en/api/quality-evaluator/latest/evaluation/evaluate-segments /openapi/phrase-quality-evaluator-latest.json post /v3/evaluation Evaluates all segments against the AI Checks resolved from the given Content Group. When no checks are associated with the Content Group, all segments are returned with an empty `results` array — no error is raised. Requires **ADMIN** or **OWNER** IDM role. # Introduction Source: https://developers.phrase.com/en/api/quality-evaluator/latest/introduction ## Quality Evaluator API Reference 1.0.0 The Quality Evaluator API uses LLMs to automatically assess translation quality against requirements you define — in plain language, not fixed rule sets. It scales the kind of review a human linguist would do: check tone, terminology, formatting, and custom requirements across any volume of segments. Quality requirements are managed as Style Guide Rules attached to a **Content Group**. Link evaluation to the Content Group and the API resolves its active Rules into AI Checks automatically — no separate profile to create or keep in sync. ### Key Features * **Content Group integration**: Quality requirements stay in sync with Style Guide Rules without manual profile maintenance * **AI Checks**: Rules are resolved into checks defined in natural language (e.g., "Translation must not use Yoda-style speech") * **Analytics**: Track evaluation metrics and AI unit consumption over time ### Base URLs The Quality Evaluator API is available in multiple regions: | Region | Base URL | | ------ | ----------------------------------------- | | EU | `https://eu.phrase.com/quality-evaluator` | | US | `https://us.phrase.com/quality-evaluator` | ### Quick Start 1. **Attach Style Guide Rules** to your Content Group (with AI Check support enabled) 2. **Evaluate segments** by referencing the Content Group — checks are resolved automatically ```bash theme={null} # Example: Evaluate segments against a Content Group's resolved AI Checks curl -X POST "https://eu.phrase.com/quality-evaluator/v3/evaluation" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "contentGroupId": "cg-abc123", "segments": [ { "id": "seg-1", "source": "Hello, world!", "target": "Hallo, Welt!" } ], "sourceLocaleCode": "en_us", "targetLocaleCode": "de_de" }' ``` # Get Quality Profile by Content Group Source: https://developers.phrase.com/en/api/quality-evaluator/latest/quality-profiles/get-quality-profile-by-content-group /openapi/phrase-quality-evaluator-latest.json get /v3/qualityProfiles/{contentGroupId} Returns the Quality Profile for the given Content Group, listing all active rules that have AI check support enabled. The profile is resolved dynamically to reflect the current state of the linked Content Group. Optionally filter by locale to retrieve only rules that apply to a specific language. # Authentication Source: https://developers.phrase.com/en/api/style-guides/authentication The Style Guide API uses Phrase Platform authentication. Generate an API token for **Phrase Style Guides** in the [Phrase Platform Settings](https://eu.phrase.com/idm-ui/settings/access-tokens), then exchange it for a JWT as described in the [Platform Authentication guide](/en/api/platform/authentication). Include the JWT in the `Authorization` header on every request: ```bash theme={null} curl -X GET "https://eu.phrase.com/styleguide/api/v1/styleguides/018e1234-5678-7890-abcd-ef1234567890" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` JWTs expire after a few hours. Re-issue a new JWT from your long-lived API token when the previous one expires; do not store JWTs at rest. # Core Concepts Source: https://developers.phrase.com/en/api/style-guides/concepts This page explains the data model behind the Style Guide API and how Style Guides, Rules, and Content Groups relate to each other and to TMS projects. **New integrations should use the v2 endpoints** (`POST /api/v2/styleguides`, `PUT /api/v2/styleguides/{id}`). They accept a `contentGroupId` parameter that links the Style Guide to a Content Group and unlocks automatic rule application in TMS projects. ## Style Guides A Style Guide is a Markdown document that captures writing guidelines for a specific language — tone, grammar rules, terminology, and formatting conventions. An organization can have one Style Guide per Content Group and language. Key properties: * **Language** — BCP-47 locale code (e.g., `en-GB`, `sv-SE`). Each Style Guide is scoped to exactly one language. * **Name and description** — human-readable metadata updated on every revision. * **Content Group** — link to a Content Group (see below). Required when using v2 endpoints. ## Versions Every time a new Markdown file is uploaded to a Style Guide, a new version is created. Versions are immutable snapshots — you cannot edit a version's file after creation, only supersede it with a new upload. Each version records: | Field | Description | | --------------------------------------- | --------------------------------------------------------------------------------- | | `versionNumber` | Monotonically increasing integer | | `name` / `description` | Metadata at the time of upload | | `changeNotes` | Optional free-text summary of what changed (`versionChangeReason` on the request) | | `fileName`, `fileSizeBytes`, `fileType` | File metadata | The Style Guide's top-level `name`, `description`, and `lastModifiedAt` always reflect the latest version. ## Rules A Rule is a single writing instruction — for example, "Avoid passive voice in all user-facing content.". Rules are used by AI Translation Agent and MT Optimize evaluate to improve translation quality. ### Origins Rules come from two sources: | Origin | How it works | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Extracted** | Automatically generated when a Style Guide is created or updated. Each distinct guideline in the Markdown file becomes a separate Rule, linked to the Style Guide. | | **Manual** | Created directly via `POST /api/v1/rules`. Useful for rules that don't belong to any Style Guide, or for adding guidelines incrementally. | ### Scope Each Rule carries two independent scope dimensions: **Content Group scope** — which Content Groups this rule applies to: * `allContentGroups: true` — rule applies across every Content Group in the organization. * `allContentGroups: false` + non-empty `contentGroupIds` — rule applies only to the listed Content Groups. **Language scope** — which languages this rule applies to: * `allLanguages: true` — rule applies to translations in every language. * `allLanguages: false` + non-empty `languages` — rule applies only to the listed locale codes. ### Lifecycle Extracted Rules start out linked to their source Style Guide (`styleGuide` field is populated). A Rule becomes **unlinked** (standalone) when a `PATCH /api/v1/rules/{id}` request does either of the following: * Edits the rule text. * **Changes** the content group or language scope in any way — including narrowing it, broadening it, or switching to `allContentGroups: true` / `allLanguages: true`. Resubmitting the exact same scope the rule already has is not a change and does not unlink it. Because unlinking is permanent, `PATCH /api/v1/rules/{id}` requires you to confirm it explicitly: if the update would unlink the rule and the request does not set `forceUnlink: true`, the API returns `409 Conflict` (`RULE_UNLINK_REQUIRES_CONFIRMATION`) and applies none of the requested changes. Retry the same request with `forceUnlink: true` to proceed. See [Working with Rules](/en/api/style-guides/rules) for an example. Unlinking turns the rule into a manual rule. The original Style Guide is unchanged. **When a new Style Guide version is uploaded**, every rule still linked to that Style Guide is deleted and replaced by the freshly extracted set. Only rules that were already **unlinked** beforehand (via a prior `forceUnlink: true` edit) survive a new version upload as standalone rules. If the updated Style Guide file still contains an equivalent guideline, the newly extracted rule can duplicate one of these surviving standalone rules. Review standalone rules that originated from a Style Guide after uploading a new version, and remove any that now duplicate a freshly extracted rule. ### Active and AI check flags Each Rule has two toggles: * `active` — disabled rules are excluded from all checks and are not used by AI Translation Agent or MT Optimize. * `aiCheckEnabled` — when `false`, the rule is excluded from AI-powered Quality Assurance checks but is still used by AI Translation Agent and MT Optimize. A rule cannot have `aiCheckEnabled: true` unless it is also active. Both flags are subject to the active-rule and AI-check limits described in [Limits](#limits) below: * Explicitly requesting `active: true` (or `aiCheckEnabled: true`) fails with `409 Conflict` if any (Content Group, Language) pair the rule applies to is already at its limit. * If the flag is omitted on create or update, the service decides it automatically: `true` if every applicable (Content Group, Language) pair still has room, `false` otherwise — no error is returned in this case. ## Content Groups A Content Group is an identifier managed by the **Content Group API** (a separate service). It is a broader Platform concept that is used to organize Assets and Projects across logical groups. In case of Style Guides, a content group acts as a shared reference point that connects Style Guides and their Rules to TMS projects. Content Groups are created and managed outside this API. The Style Guide API accepts a Content Group ID as an opaque string — use the Content Group API to create and list groups. ## How Everything Connects ``` Style Guide (language: en-GB) ├── linked to → Content Group "marketing" └── source of → Rules (each scoped to Content Group "marketing", language en-GB) TMS Project └── linked to → Content Group "marketing" └── at translation time, applies all active Rules where: contentGroupIds contains "marketing" (or allContentGroups = true) AND languages contains job language (or allLanguages = true) ``` ### TMS project integration In previous versions of the API, a TMS project had to be linked to a Style Guide per target language. With Content Groups, the workflow changes: 1. Create a Style Guide with a `contentGroupId` (v2 endpoint). 2. Link the TMS project to the same Content Group (via TMS project settings). 3. When a translation job runs, the AI Translation Agent and MT Optimize automatically pick up all active Rules whose content group and language scope match the job's Content Group and target language. This means a single Content Group can aggregate Rules from multiple Style Guides across languages, and one Style Guide can serve multiple projects through a shared Content Group. Rule changes — whether made directly via the Rules API or triggered by uploading a new Style Guide version — take effect immediately for any running jobs in that Content Group. To avoid unintended effects on in-flight translations, make rule changes when no jobs for that Content Group are active. You can update and review rules before starting new jobs to verify they produce the expected results. ## Limits | Limit | Value | Scope | | ---------------------------------- | -------------- | --------------------------------------- | | Active rules | 50 | Per (Content Group, Language) pair | | Active rules with AI check enabled | 20 | Per (Content Group, Language) pair | | Rule text length | 450 characters | Per rule | | Content Groups per rule | 100 | Per rule (`contentGroupIds`) | | Languages per rule | 100 | Per rule (`languages`) | | Content Group / language filters | 50 | Per `POST /api/v1/rules/search` request | **Active-rule limit** — no more than 50 rules may be active at once for any single (Content Group, Language) pair. A rule counts toward a pair's limit if it's active and linked to that Content Group (directly, or via `allContentGroups: true`) and that Language (directly, or via `allLanguages: true`). A rule linked to multiple Content Groups or Languages is checked against every pair it applies to — the request is rejected if any one of them is full. **AI-check limit** — no more than 20 active rules may have `aiCheckEnabled: true` at once for any single (Content Group, Language) pair, using the same direct-or-global linkage rule. A rule cannot have AI check enabled unless it is also active. Requests that would explicitly push a pair over either limit are rejected with `409 Conflict` (`ACTIVE_RULE_LIMIT_REACHED` or `AI_CHECK_LIMIT_REACHED`), identifying the limit and the affected Content Group and Language. See [Working with Rules](/en/api/style-guides/rules) for an example. **Style Guide extraction and the limits** — extracting rules from a Style Guide never touches the active or AI-check status of rules that were already active for that Content Group and Language. If a batch of newly extracted rules would exceed the remaining room, only as many as fit — taken in the order they appear in the Markdown file — are kept active (and AI-check-enabled); the rest are still saved, just inactive. The `extractedRulesCount` in the create/update response always reflects the full extracted count, regardless of how many ended up active. ## Summary | Resource | Scope | Created by | | ------------- | ---------------------------------------------------- | --------------------------------------- | | Style Guide | One per Content Group & language per organization | API upload (v1 or v2) | | Version | One per file upload | Automatic on Style Guide create/update | | Rule | Many per Style Guide; standalone rules also possible | Automatic extraction or manual creation | | Content Group | Organization-wide | Content Group API | For step-by-step API usage, see [Working with Rules](/en/api/style-guides/rules) and the **API Documentation** section in the left navigation. # Introduction Source: https://developers.phrase.com/en/api/style-guides/introduction ## Style Guide API Reference The Style Guide API lets you manage organization-wide writing guidelines that Phrase applies across translations and authored content. A Style Guide is a Markdown document scoped to a single language and versioned on every revision. Rules are automatically extracted from each Style Guide and can also be created manually — they improve the output quality in AI Translation Agent and MT Optimize. **New integrations should use the v2 endpoints** (`POST /api/v2/styleguides`, `PUT /api/v2/styleguides/{id}`). The v2 endpoints require a Content Group ID, which enables automatic rule application in TMS projects. The v1 create and update endpoints are deprecated. ### Key Features * **Markdown-first authoring** — upload Markdown files; the active version is always the latest revision * **Multi-language** — manage one Style Guide per language * **Versioning** — every revision is stored with optional change notes; previous versions stay accessible * **Rules** — rules extracted automatically from each Style Guide, or created manually; improve AI Translation Agent and MT Optimize output quality * **Content Group integration** — link a Style Guide to a Content Group so TMS projects inherit its rules automatically * **Search and filter** — find Style Guides by name, description, language, or last-modified date * **Bulk delete** — remove multiple Style Guides in a single call, with per-item success / failure reporting Active rules are capped at 50, and active rules with AI check enabled are capped at 20, per (Content Group, Language) pair. See [Limits](/en/api/style-guides/concepts#limits) for details. ### Base URLs The Style Guide API is available in multiple regions: | Region | Base URL | | ------ | ---------------------------------- | | EU | `https://eu.phrase.com/styleguide` | | US | `https://us.phrase.com/styleguide` | ### Quick Start 1. **Exchange your API token** for a JWT via the [Platform Authentication guide](/en/api/platform/authentication) 2. **Create a Style Guide** by uploading a Markdown file with a Content Group ID 3. **Poll the job status** endpoint until the job completes 4. **Reference the Style Guide** by ID in subsequent calls ```bash theme={null} curl -X POST "https://eu.phrase.com/styleguide/api/v2/styleguides" \ -H "Authorization: Bearer $JWT" \ -F language=en-GB \ -F name="English Style Guide" \ -F description="Brand voice and grammar rules" \ -F contentGroupId="my-content-group" \ -F file=@./style-guide.md ``` The response returns a `jobId`. Poll **Get create job status** until `status` is `COMPLETED`: ```bash theme={null} curl "https://eu.phrase.com/styleguide/api/v1/styleguides/async/create-jobs/$JOB_ID" \ -H "Authorization: Bearer $JWT" ``` Browse the full operation set, request and response schemas, and per-endpoint examples in the **API Documentation** section of the left navigation. For a conceptual overview of Style Guides, Rules, and Content Groups, see [Core Concepts](/en/api/style-guides/concepts). # Create a Rule Source: https://developers.phrase.com/en/api/style-guides/rule/create-a-rule /openapi/phrase-style-guides.json post /api/v1/rules Creates a Rule for the authenticated organization. When omitted, active and aiCheckEnabled each default to true, but only if doing so would not exceed the active-rule limit (50) or AI-check limit (20) for every (Content Group, Language) pair the rule applies to; otherwise they default to false. Explicit true values that would exceed a limit are rejected with 409 CONFLICT. # Delete a Rule Source: https://developers.phrase.com/en/api/style-guides/rule/delete-a-rule /openapi/phrase-style-guides.json delete /api/v1/rules/{id} Permanently deletes a Rule. # Get a Rule Source: https://developers.phrase.com/en/api/style-guides/rule/get-a-rule /openapi/phrase-style-guides.json get /api/v1/rules/{id} Returns a Rule by ID. # List Rules Source: https://developers.phrase.com/en/api/style-guides/rule/list-rules /openapi/phrase-style-guides.json post /api/v1/rules/search Returns a paginated, sorted list of Rules. Defaults to creation date descending. # Update a Rule Source: https://developers.phrase.com/en/api/style-guides/rule/update-a-rule /openapi/phrase-style-guides.json patch /api/v1/rules/{id} Updates a Rule. Only fields present (non-null) in the request body are applied. Editing the text, or removing the linked Style Guide's content group or language, would unlink the rule from its Style Guide; set forceUnlink=true to confirm, otherwise the request fails with 409 CONFLICT and no changes are applied. # Working with Rules Source: https://developers.phrase.com/en/api/style-guides/rules Rules are the writing instructions that Phrase uses to improve the translation quality for AI Translation Agent and MT Optimize. Rules are also used for AI-powered quality checks. This guide walks through the full lifecycle: from uploading a Style Guide and inspecting the extracted rules, to creating manual rules and updating them over time. For a conceptual overview of how Rules relate to Style Guides and Content Groups, see [Core Concepts](/en/api/style-guides/concepts). ## Extracted rules vs manual rules | | Extracted | Manual | | ------------------------- | --------------------------------------------------------------------------------------------------------- | ----------------------------- | | **Created by** | Automatic, on Style Guide create or update | `POST /api/v1/rules` | | **Linked to Style Guide** | Yes (`styleGuide` field populated) | No | | **Scope on creation** | Inherits Style Guide's Content Group and language | Set explicitly in the request | | **Unlinked when** | Rule text is edited, or content group/language scope is changed in any way (requires `forceUnlink: true`) | Never linked to begin with | Use extracted rules when your team maintains a Style Guide Markdown file as the source of truth. Use manual rules for guidelines that live outside any Style Guide, or when you want to add or override individual rules without uploading a new file. ## End-to-end walkthrough ### 1. Create a Style Guide Upload a Markdown file using the v2 endpoint with a Content Group ID. The API returns a `jobId` immediately and processes the file asynchronously. ```bash theme={null} curl -X POST "https://eu.phrase.com/styleguide/api/v2/styleguides" \ -H "Authorization: Bearer $JWT" \ -F language=en-GB \ -F name="English Style Guide" \ -F contentGroupId="6a428641ba54ab39ae56da64" \ -F file=@./style-guide.md ``` Response: ```json theme={null} { "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" } ``` ### 2. Poll the create job ```bash theme={null} curl "https://eu.phrase.com/styleguide/api/v1/styleguides/async/create-jobs/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer $JWT" ``` Keep polling until `status` is `COMPLETED`. The `result` field contains the created Style Guide. ```json theme={null} { "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "COMPLETED", "result": { "id": "018e1234-5678-7890-abcd-ef1234567890", "name": "English Style Guide", "language": { "bcpCode": "en-GB", "description": "English (United Kingdom)", "language": "en" }, "contentGroup": { "id": "6a428641ba54ab39ae56da64" } } } ``` ### 3. List extracted rules After the job completes, list the rules that were extracted from the Style Guide. Filter by `styleGuideIds` to retrieve only rules from this guide. ```bash theme={null} curl -X POST "https://eu.phrase.com/styleguide/api/v1/rules/search" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "styleGuideIds": ["018e1234-5678-7890-abcd-ef1234567890"], "pageNumber": 0, "pageSize": 20 }' ``` Each rule in the response includes its extracted text, scope, and a `styleGuide` reference pointing back to the source: ```json theme={null} { "content": [ { "id": "01900000-0000-7000-8000-000000000001", "rule": "Avoid passive voice in all user-facing content.", "active": true, "aiCheckEnabled": true, "allContentGroups": false, "allLanguages": false, "contentGroups": [{ "id": "6a428641ba54ab39ae56da64" }], "languages": [{ "bcpCode": "en-GB", "description": "English (United Kingdom)", "language": "en" }], "styleGuide": { "id": "018e1234-5678-7890-abcd-ef1234567890" } } ], "totalElements": 12, "totalPages": 1, "pageNumber": 0, "pageSize": 20, "numberOfElements": 12 } ``` ### 4. Edit a rule Use `PATCH /api/v1/rules/{id}` to update a rule. Only fields present (non-null) in the request body are applied — omit a field to leave it unchanged. Editing a rule's text or scope **unlinks it from its source Style Guide**. The `styleGuide` field becomes `null` and the rule becomes standalone. This does not affect the Style Guide itself or its other extracted rules. Because this is permanent, the API will not perform an unlinking update unless the request explicitly sets `forceUnlink: true`. Without it, the request fails with `409 Conflict` (`RULE_UNLINK_REQUIRES_CONFIRMATION`) and none of the requested changes are applied. ```bash theme={null} curl -X PATCH "https://eu.phrase.com/styleguide/api/v1/rules/01900000-0000-7000-8000-000000000001" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "rule": "Use active voice in all user-facing content." }' ``` Since this rule is linked to a Style Guide, the request above fails: ```json theme={null} { "code": "RULE_UNLINK_REQUIRES_CONFIRMATION", "message": "This update would unlink the rule from its Style Guide. Set forceUnlink=true to confirm.", "detail": "Updating rule 01900000-0000-7000-8000-000000000001 would unlink it from its Style Guide" } ``` Retry with `forceUnlink: true` to confirm the unlink and apply the change: ```bash theme={null} curl -X PATCH "https://eu.phrase.com/styleguide/api/v1/rules/01900000-0000-7000-8000-000000000001" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "rule": "Use active voice in all user-facing content.", "forceUnlink": true }' ``` Updates that do not change the rule text, content group scope, or language scope at all (for example, only toggling `active` or `aiCheckEnabled`, or resubmitting the same scope the rule already has) never unlink the rule, so `forceUnlink` is not required for them. Rule changes take effect immediately for any running jobs in the affected Content Group. Make rule edits when no jobs for that Content Group are active, and verify your rules before starting new jobs. ## Creating a manual rule ```bash theme={null} curl -X POST "https://eu.phrase.com/styleguide/api/v1/rules" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "rule": "Use the Oxford comma in all list items.", "allContentGroups": false, "contentGroupIds": ["6a428641ba54ab39ae56da64", "6a2eb0d1ed7a69bbb1b53d06"], "allLanguages": false, "languages": ["en-GB", "en-US"], "active": true, "aiCheckEnabled": true }' ``` To create a rule that applies everywhere, set both `allContentGroups` and `allLanguages` to `true` and omit `contentGroupIds` and `languages`: ```bash theme={null} curl -X POST "https://eu.phrase.com/styleguide/api/v1/rules" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "rule": "Do not use exclamation marks in formal content.", "allContentGroups": true, "allLanguages": true }' ``` ## Active-rule and AI-check limits Each (Content Group, Language) pair may have at most 50 active rules and 20 active rules with AI check enabled. See [Limits](/en/api/style-guides/concepts#limits) for the full definition. If you explicitly request `active: true` (or `aiCheckEnabled: true`) and the affected pair is already at its limit, the request is rejected and no rule is created or changed: ```bash theme={null} curl -X POST "https://eu.phrase.com/styleguide/api/v1/rules" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "rule": "Use the Oxford comma in all list items.", "allContentGroups": false, "contentGroupIds": ["6a428641ba54ab39ae56da64"], "allLanguages": false, "languages": ["en-GB"], "active": true }' ``` ```json theme={null} { "code": "ACTIVE_RULE_LIMIT_REACHED", "message": "The active rule limit (50) has been reached for this Content Group and Language.", "detail": "Content Group 6a428641ba54ab39ae56da64, Language en-GB already has 50 active rules" } ``` `aiCheckEnabled: true` requests fail the same way with `AI_CHECK_LIMIT_REACHED` once a pair already has 20 active, AI-check-enabled rules. Requesting `aiCheckEnabled: true` without the rule being (or becoming) active is rejected separately as an invalid request, before the AI-check limit is evaluated. If you omit `active` or `aiCheckEnabled` instead of setting them explicitly, the API never returns a limit error for that flag — it sets the flag to `true` only if there's room, and to `false` otherwise: ```bash theme={null} curl -X POST "https://eu.phrase.com/styleguide/api/v1/rules" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "rule": "Use the Oxford comma in all list items.", "allContentGroups": false, "contentGroupIds": ["6a428641ba54ab39ae56da64"], "allLanguages": false, "languages": ["en-GB"] }' ``` ## Filtering rules The `POST /api/v1/rules/search` endpoint supports several filters that can be combined: | Filter | Description | | ----------------- | ----------------------------------------------------- | | `contentGroupIds` | Return rules scoped to any of these Content Group IDs | | `languages` | Return rules scoped to any of these locale codes | | `styleGuideIds` | Return only rules extracted from these Style Guides | | `active` | `true` / `false` — filter by active status | | `aiCheckEnabled` | `true` / `false` — filter by AI check flag | | `ruleText` | Case-insensitive substring match against rule text | | `lastModifiedBy` | Filter by user account IDs | Example — find all active rules for the `marketing` Content Group in English: ```bash theme={null} curl -X POST "https://eu.phrase.com/styleguide/api/v1/rules/search" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "contentGroupIds": ["6a428641ba54ab39ae56da64"], "languages": ["en-GB"], "active": true, "pageNumber": 0, "pageSize": 50 }' ``` ## Disabling a rule for AI checks Set `aiCheckEnabled: false` to keep a rule in the Style Guide record without using it for AI-powered Quality checks. This is useful for rules that are aspirational or under review. ```bash theme={null} curl -X PATCH "https://eu.phrase.com/styleguide/api/v1/rules/01900000-0000-7000-8000-000000000001" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "aiCheckEnabled": false }' ``` To re-enable, patch with `"aiCheckEnabled": true`. ## Deleting a rule `DELETE /api/v1/rules/{id}` permanently removes a rule. This does not affect the source Style Guide or any other extracted rules. ```bash theme={null} curl -X DELETE "https://eu.phrase.com/styleguide/api/v1/rules/01900000-0000-7000-8000-000000000001" \ -H "Authorization: Bearer $JWT" ``` A successful deletion returns `204 No Content`. # Create a Style Guide Source: https://developers.phrase.com/en/api/style-guides/style-guide/create-a-style-guide /openapi/phrase-style-guides.json post /api/v1/styleguides **Deprecated** — use `POST /api/v2/styleguides` for new integrations. Creates a Style Guide from a Markdown file. Returns 202 with a jobId; poll the **Get create job status** API for the final result. # Create a Style Guide (v2) Source: https://developers.phrase.com/en/api/style-guides/style-guide/create-a-style-guide-v2 /openapi/phrase-style-guides.json post /api/v2/styleguides Creates a Style Guide from a Markdown file with a Content Group. Returns 202 with a jobId; poll the **Get create job status** API for the final result. # Delete Style Guides Source: https://developers.phrase.com/en/api/style-guides/style-guide/delete-style-guides /openapi/phrase-style-guides.json delete /api/v1/styleguides Deletes the listed Style Guides and all of their versions. Partial success is possible; the response reports the deleted count and per-item failures. # Get a Style Guide Source: https://developers.phrase.com/en/api/style-guides/style-guide/get-a-style-guide /openapi/phrase-style-guides.json get /api/v1/styleguides/{id} Returns a Style Guide. # Get create job status Source: https://developers.phrase.com/en/api/style-guides/style-guide/get-create-job-status /openapi/phrase-style-guides.json get /api/v1/styleguides/async/create-jobs/{jobId} Returns the current state of a Style Guide create job. HTTP status is always 200; switch on the body's status field. # Get update job status Source: https://developers.phrase.com/en/api/style-guides/style-guide/get-update-job-status /openapi/phrase-style-guides.json get /api/v1/styleguides/async/update-jobs/{jobId} Returns the current state of a Style Guide update job. HTTP status is always 200; switch on the body's status field. # List Style Guides Source: https://developers.phrase.com/en/api/style-guides/style-guide/list-style-guides /openapi/phrase-style-guides.json post /api/v1/styleguides/search Returns a paginated list of Style Guides. Filter by name, language, last-modified range, or last-modified user; sort by name, language, or last-modified date. # Update a Style Guide Source: https://developers.phrase.com/en/api/style-guides/style-guide/update-a-style-guide /openapi/phrase-style-guides.json put /api/v1/styleguides/{id} **Deprecated** — use `PUT /api/v2/styleguides/{id}` for new integrations. Updates a Style Guide. When a new file is uploaded, returns 202 with a jobId; poll the **Get update job status** API for the final result. Metadata-only updates return 200 with the updated Style Guide. Content-Type can be omitted for metadata-only updates; use multipart/form-data when uploading a file. # Update a Style Guide (v2) Source: https://developers.phrase.com/en/api/style-guides/style-guide/update-a-style-guide-v2 /openapi/phrase-style-guides.json put /api/v2/styleguides/{id} Updates a Style Guide with a Content Group. When a new file is uploaded, returns 202 with a jobId; poll the **Get update job status** API for the final result. Metadata-only updates return 200 with the updated Style Guide. Content-Type can be omitted for metadata-only updates; use multipart/form-data when uploading a file. # Changelog Source: https://developers.phrase.com/en/changelog Stay up to date with the latest changes to Phrase APIs, SDKs, and developer tools. For full product release notes, see the [Phrase Help Center](https://support.phrase.com/hc/en-us/categories/4930539748124-Release-notes). ## TMS API: due date schemes, user profile, and connector helpers Several new TMS endpoints are now available: * **Due Date Schemes** — create, list, get, edit, and batch-delete due date schemes. Attach one to a service to auto-calculate due dates for a project and its jobs when created via a Submitter Portal or Automated Project Creation. * **User profile** — `GET /api2/v1/userProfile` and `PUT /api2/v1/userProfile` let the current user read and update their own profile without needing user-management rights. * **Suggested providers for multiple jobs** — `POST /api2/v2/projects/{projectUid}/jobs/providers/suggest` returns provider suggestions for a batch of jobs in one call. * **Connector auth page URL** and **Test connection of existing connector** — programmatically kick off the connector OAuth flow and verify that a saved connector still works. See the [TMS API reference](/en/api/tms/latest/introduction). ## TMS API: per-language machine translate settings on project templates `PUT /api2/v3/projectTemplates/{projectTemplateUid}/mtSettings` now accepts a `machineTranslateSettingsPerLangs` array so you can update MT settings for specific target locales only, leaving the other locales untouched. If both `machineTranslateSettings` and `machineTranslateSettingsPerLangs` are set, the per-language values take precedence. When a template is currently in bulk mode (one setting for all locales) and you switch to per-language mode, the bulk value is copied onto every locale you don't list before being cleared, so effective settings for other locales don't change as a side effect. See the [TMS API reference](/en/api/tms/latest/introduction). ## TMS API: edit multiple LQA assessments in one call The new `PUT /api2/v1/lqa/assessments/edit` endpoint marks multiple Language Quality Assessments as edited in a single request, so you no longer need to loop over jobs one by one. See the [TMS API reference](/en/api/tms/latest/introduction). ## Service Accounts: Machine-to-Machine authentication Server-to-server integrations can now authenticate without a human user in the loop. Create a Service Account in **Organization Settings → Service Accounts** to get a `client_id`/`client_secret` pair and exchange them directly for an access token via the standard OAuth 2.0 Client Credentials flow — no API token or token-exchange step needed. * Each Service Account provisions a bot user scoped to one or more Phrase products. * Bot users can read/write content, run analyses, and work with translation memories, but can't create or modify human users, or be assigned as project owners. They don't count toward seat quotas. See the [Platform authentication guide](/en/api/platform/authentication#machine-to-machine-authentication-service-accounts). ## Content Groups API: SYSTEM content group Every organization now has one platform-managed **SYSTEM** content group ("All Groups"), representing "applies to all content groups." `Group` objects now carry a `groupType` field (`SYSTEM` or `USER`), and references now carry a `referenceType` field (`SYSTEM` or `USER`). * Use the literal string `SYSTEM` as an alias for the group id on `GET /groups/{groupId}` and `GET /groups/{groupId}/references`. It is not accepted on `PUT`/`DELETE /groups/{groupId}` — the SYSTEM group is immutable and those calls return `403`. * `listGroups` and `listGroupReferences` accept a new `includeSystem` query parameter (default `true`) to include/exclude the SYSTEM group and its references. * `PLATFORM_STYLE_GUIDE`, `TMS_PROJECT`, and the newly added `TMS_PROJECT_TEMPLATE` object type are never linked to the SYSTEM group; only `PLATFORM_QA_CHECK` and `PLATFORM_STYLE_RULE` references can appear under it. See the [Content Groups API reference](/en/api/control-hub/introduction#the-system-content-group). ## Style Guide API: active-rule and AI-check limits per Content Group and Language Each (Content Group, Language) pair now allows at most **50 active rules** and **20 active rules with AI check enabled**. Rules are counted whether linked directly to a Content Group/Language or via `allContentGroups`/`allLanguages`. * Explicitly requesting `active: true` or `aiCheckEnabled: true` when a pair is already at its limit is rejected with `409 Conflict` (`ACTIVE_RULE_LIMIT_REACHED` / `AI_CHECK_LIMIT_REACHED`). * When these flags are omitted, the API now decides them automatically based on remaining room, instead of always defaulting to `true`. * Style Guide rule extraction respects the same limits: extracted rules beyond the remaining room are saved but left inactive, without affecting rules already active for that Content Group and Language. See [Limits](/en/api/style-guides/concepts#limits) in the Style Guide API reference. ## Studio API: AI model value `quokka` is now `aita` The AI model name enums for the [Update project settings](/en/api/studio/projects/update-project-settings) endpoint (`chatModelName`, `insightsModelName`, and `translationModelName`) previously exposed the internal codename `quokka`. The AI Translation Agent is now selected with the value `aita` — a meaningful external name in line with the other options (`plai`, `gpt-5-mini`, `gpt-4o-mini`). * Use `aita` when setting one of these fields to the AI Translation Agent. * The old `quokka` value is still accepted for backward compatibility, but is no longer documented and may be removed in a future release. See the [Studio API reference](/en/api/studio/introduction). ## Content Groups API now available The [Content Groups API](/en/api/control-hub/introduction) is now documented in the Developer Hub. Use it to manage **content groups** — organization-scoped collections that link platform objects such as projects, style guides, style rules, and AI quality checks together for coordinated workflows. ## Strings API: job automations can target multiple projects Job automations previously accepted `project_ids` as an array but used only the first entry. You can now associate a job automation with **multiple projects** in a single call. Multi-project automations require the `advanced_job_automation` plan feature — accounts without it receive a `422` with `project_ids` in the error field. See the [Strings API reference](/en/api/strings/introduction). ## Studio API: clarified subtitle updates — `words` is the source of truth The Update/Get Subtitle reference now spells out that a segment's `words` array (word-level text and timings) is authoritative for both subtitle rendering and dubbing text-to-speech. The `text` field is only a human-readable mirror and is ignored when rendering or synthesizing. * To change what a segment says (for example, shortening a dubbing line before a redub), edit its `words` — not just `text`. * Never submit a segment with an empty `words` array: it is silently dropped the next time the track is read, and produces no dubbing audio. This is the usual cause of a track that "comes back empty" after an update. * The endpoint is a bulk replace: always send the full segment list, then list changed ids in `segmentsToRedub` to regenerate their audio. See the [Studio API reference](/en/api/studio/introduction). ## Quality Evaluator API: v1 CRUD and v2 endpoints deprecated All v1 AI Check CRUD endpoints (`GET/POST /v1/aiChecks`, `GET/PUT/DELETE /v1/aiChecks/{uid}`), v1 Quality Profile CRUD endpoints, `PUT /v2/aiChecks/{uid}`, and `POST /v2/evaluation` are now flagged as **deprecated** in the OpenAPI spec. Migrate to the v3 Content Group–based endpoints: * `POST /v3/evaluation` for evaluating segments. * `GET /v3/qualityProfiles/{contentGroupId}` for resolving a Quality Profile from a Content Group. The deprecated endpoints continue to work for now. See the [Quality Evaluator API reference](/en/api/quality-evaluator/introduction). ## Strings API: link and unlink keys with content strategies The Key Links endpoints now cover the full lifecycle of shared translations between a parent key and its children: * **Link child keys** — designate a parent and attach one or more children so their translations derive from the parent. * **List child keys** — retrieve the full link record for a parent, including all attached children. * **Unlink a single child** — detach one child; its translations inherit the parent's current content and are marked unverified for reviewer confirmation. * **Batch unlink** — detach several children in one request, or dissolve the entire group with `unlink_parent: true`. * **Content strategy on unlink** — choose `keep_content` (default; copies the parent's translations into each detached child) or `remove_content` (clears them). Key Links are available on main projects only. See the [Strings API reference](/en/api/strings/introduction). ## Strings API: document list search is now a prefix match The `q` parameter on **List documents** now performs a case-insensitive **prefix** match on the document name instead of a substring match. For example, `q=invoice` returns documents whose names *start* with "invoice", not those that merely contain it. If you relied on the previous substring behavior, adjust your queries accordingly. The **Delete document**, **Get screenshot**, and **Delete screenshot** endpoints also received clearer descriptions and error contracts. See the [Strings API reference](/en/api/strings/introduction). ## Strings API: assign a Language AI profile per locale Locales now accept an optional `language_ai_profile` identifier when you create or update a locale. The selected profile drives Language AI behavior for that locale, and the assigned profile is returned on the locale resource. See the [Strings API reference](/en/api/strings/introduction). ## Strings API: prefix-based locale downloads Locale download requests now accept two related options in the request body: * **`translation_key_prefix`** — strip the given prefix from key names in the exported file. * **`filter_by_prefix`** — when `true`, only export keys that match `translation_key_prefix`, and remove the prefix from the output. Use these to export a subset of keys with cleaner names. Note: stripping a prefix can produce duplicate key names if other keys collide once the prefix is removed. See the [Strings API reference](/en/api/strings/introduction). ## Connectors API: full reference for all seven connectors The Connectors API reference now documents every supported connector end-to-end, not just Contentful. Available connectors: * **Files** — sync localizable files from arbitrary file sources. * **GitHub** — connect repositories to TMS projects. * **Braze** — pull content blocks and email templates for translation. * **Contentful** — sync entries and assets. * **Google Drive** — translate documents stored in Drive. * **Tridion Docs** — exchange content with Tridion Docs. * **Optimizely** — localize Optimizely content. Each connector exposes the same request/response contract, so you can build custom flows against a consistent interface. See the [Connectors API reference](/en/api/connectors/introduction). ## Strings API: review due dates on jobs Job responses now include a `review_due_date` field so you can see when a job's review stage is due. The field returns `null` when the project does not have the review workflow enabled. See the [Strings API reference](/en/api/strings/introduction). ## Strings API: branch comparison response schema The branch comparison endpoint now returns a fully described response. For each resource type (translation keys, translations, locales, tags), the response lists changes made on the base branch, changes made on the feature branch, and any conflicts — making it easier to surface branch diffs and resolve merges programmatically. See the [Strings API reference](/en/api/strings/introduction). ## Quality Evaluator API v3: Content Group–based evaluation Quality Evaluator now resolves AI Checks and Quality Profiles dynamically from Content Groups, so a single call applies the right checks for the target content: * **Evaluate against a Content Group** — `POST /v3/evaluation` evaluates segments using the AI Checks resolved from the supplied `contentGroupId`. When no checks are associated, segments are returned with an empty `results` array instead of an error. * **Resolve a Quality Profile** — `GET /v3/qualityProfiles/{contentGroupId}` returns the Quality Profile resolved for a Content Group. * **Restrict AI Checks to specific locales** — `PUT /v2/aiChecks/{uid}` accepts an optional `locales` field so a check can be limited to certain target locales. Omit the field to preserve existing restrictions, or send an empty array to clear them. The previous AI Check CRUD endpoints (`/v1/aiChecks*`), Quality Profile CRUD endpoints (`/v1/qualityProfiles*`), and `POST /v2/evaluation` are now deprecated. Migrate to the v3 Content Group–based endpoints. See the [Quality Evaluator API introduction](/en/api/quality-evaluator/introduction). ## Strings API: name your repo syncs Repo syncs now support an optional `name` field (up to 100 characters) so you can give each sync a custom display name. When the name is null or blank, the sync continues to display using its associated project name. Set `name` when creating or updating a repo sync to make repository connections easier to identify in lists and dashboards. See the [Strings API reference](/en/api/strings/introduction). ## Studio API: update projects and manage recording subtitles Three new endpoints expand what you can do with the Studio API: * **Update project settings** — `PATCH /v1/projects/{id}` partially updates AI model preferences, TTS provider, translation memory / MT profile assignment, and sharing visibility. Only the fields you send are changed. * **Get recording subtitles** — `GET /v1/projects/{projectId}/recordings/{recordingId}/subtitles` returns the segmented subtitle for a recording. * **Update recording subtitles** — `PUT /v1/projects/{projectId}/recordings/{recordingId}/subtitles` writes subtitle segments back to a recording. See the [Studio API reference](/en/api/studio/introduction). ## TMS API: link projects to content groups Three new TMS endpoints let you manage a project's content group association: * `GET /api2/v1/projects/{projectUid}/contentGroup` — get the content group linked to a project. * `POST /api2/v1/projects/{projectUid}/contentGroup` — link a project to a content group. * `DELETE /api2/v1/projects/{projectUid}/contentGroup` — unlink a project from its content group. See the [TMS API reference](/en/api/tms/latest/introduction). ## TMS: quality evaluation moved under projects, plus segment warnings storage The endpoint that triggers AI quality evaluation has moved to a project-scoped path: * **New:** `POST /api2/v1/projects/{projectUid}/jobs/evaluateQuality` * **Replaces:** `POST /api2/v1/qualityProfiles/evaluate` A new `POST /api2/v1/qualityProfiles/segmentWarnings` endpoint also lets you store evaluation warnings for a job part. Update any integrations that called the previous endpoint. See the [TMS API reference](/en/api/tms/latest/introduction). ## Strings API: larger upload size for unmentioned-key reporting When you upload translations, the response field that counts keys not mentioned in the upload is now calculated for uploads up to **100,000 keys** (previously 10,000). Larger uploads still report `0`. See the [Strings API reference](/en/api/strings/introduction). ## SCIM endpoints moved to the Platform API SCIM user provisioning is now part of the Phrase Platform API at `/scim/...` (for example, `GET /scim/Users`, `POST /scim/Users`, `GET /scim/ServiceProviderConfig`). The previous `/api2/v1/scim/...` paths under TMS have been removed. Point your SCIM identity provider at the Platform endpoints. See the [Platform API reference](/en/api/platform/introduction). ## Strings API: fall back to another locale for unverified translations Locale download endpoints accept a new optional query parameter, `fallback_for_unverified_translations`. When `true`, translations in a non-final state are replaced by the fallback locale's translation at export time: * In the **simple** workflow, "non-final" means `unverified`. * In the **review** workflow, it also includes `translated` (awaiting review). No stored translations are modified. Requires `fallback_locale_id` or `use_locale_fallback` to be set. See the [Strings API reference](/en/api/strings/introduction). ## Strings API: Identify how jobs were created Job responses in the Strings API now include two new fields so you can see where a job came from: * **`automation_id`** — the ID of the automation that created the job, or `null` if it was created manually * **`job_template_id`** — the ID of the job template the job was created from, or `null` if no template was used See the [Strings API reference](/en/api/strings/introduction) for the updated schema. ## MCP Server v0.10.0: Strings Repo Sync The Phrase MCP Server `v0.10.0` adds Repo Sync tools for Strings, so you can manage repository synchronization between Strings projects and Git repositories directly from your MCP client. See the [MCP Server guide](/en/guides/mcp) for full details. ## TMS: Quality estimation warnings and translation memory alignment Two new TMS API endpoints are available: * **Quality estimation warnings** — `POST /api2/v1/qualityProfiles/qeWarnings` returns AI-generated QE warnings for selected job parts, paginated by segment. * **Translation memory alignment** — `POST /api2/v2/transMemories/{transMemoryUid}/align` aligns supplied source and target files using the TM's source locale and returns an aligned XLSX file. See the [TMS API reference](/en/api/tms/latest/introduction) for details. ## Quality evaluation: lock and confirm passing segments The TMS endpoint that triggers AI quality evaluation accepts two new optional parameters: * `lockSegments` (default `true`) — locks segments that pass all AI checks. * `confirmSegments` (default `false`) — confirms segments that pass all AI checks. Use these to automate post-evaluation segment status changes. See the [TMS API reference](/en/api/tms/latest/introduction). ## Style Guides API The Style Guide API is now public. Manage organization-wide writing guidelines through the API: create and update Markdown style guides per language, version every revision, search and filter, and bulk-delete. See the [Style Guides API Reference](/en/api/style-guides/introduction) to get started. ## MCP Server v0.9.0: Analysis and Quotes for TMS The Phrase MCP Server `v0.9.0` now supports the TMS Analysis and Quotes APIs. New tools let you create and manage analyses and quotes directly from your MCP client. See the [MCP Server guide](/en/guides/mcp) for full details. ## MCP Server v0.8.0: Strings screenshots The Phrase MCP Server `v0.8.0` adds screenshot support for Strings with new `create_screenshot` and `create_screenshot_marker` tools, so you can attach visual context to keys directly from your MCP client. See the [MCP Server guide](/en/guides/mcp) for full details. ## MCP Server v0.7.0: Google Drive connector, Quality Evaluator, and base64 uploads The Phrase MCP Server `v0.7.0` adds several new capabilities: * **Google Drive connector** — manage Google Drive connector resources from the MCP Server * **Quality Evaluator** — evaluate translation quality through new Quality Evaluator tools * **Base64 file uploads** — file upload tools now accept base64-encoded `file_content` as an alternative to `file_path` See the [MCP Server guide](/en/guides/mcp) for full details. ## Quality Evaluator API The new Quality Evaluator API enables automated, AI-powered assessment of translation quality. Define quality requirements in natural language, group them into reusable profiles, and evaluate translation segments at scale. * **AI Checks** — create custom checks from natural language quality requirements * **Quality Profiles** — group AI Checks into reusable profiles * **Analytics** — track evaluation metrics and AI unit consumption over time See the [Quality Evaluator API introduction](/en/api/quality-evaluator/introduction) to get started. ## MCP Server: Termbase and Translation Memory management The Phrase MCP Server now supports managing Termbases and Translation Memories in TMS. New tools are available for: * **Termbases** — list, get details, search, import, and export * **Translation Memories** — list, get details, search, import, and export These tools are available as part of the TMS product in the MCP Server. See the [MCP Server guide](/en/guides/mcp) for full details. ## MCP Server package renamed The Phrase MCP Server npm package has been renamed and is now published under the `@phrase` organization. **Before:** ```json theme={null} "args": ["-y", "phrase-mcp-server"] ``` **After:** ```json theme={null} "args": ["-y", "@phrase/phrase-mcp-server"] ``` Update your MCP client configuration to use the new package name. The old `phrase-mcp-server` package is no longer maintained. See the [MCP Server quick start](/en/guides/mcp) for full configuration examples. # Introduction Source: https://developers.phrase.com/en/developer-tools/introduction Tools and libraries to integrate with Phrase APIs Phrase provides a collection of developer tools to help you integrate with our APIs efficiently. These tools simplify common tasks like pushing and pulling translation files, and provide access to our APIs in your preferred programming language. ## Available tools A command-line tool for macOS, Linux, and Windows that provides direct access to the Phrase Strings API. Push and pull translation files, manage keys, and automate your localization workflow. Official API client libraries for Ruby, Python, PHP, TypeScript, Java, and Go. Integrate Phrase Strings directly into your applications. A GitHub Action that installs the Phrase CLI in your workflow, enabling automated push and pull of translation files in your CI/CD pipeline. # Phrase Strings API Clients Source: https://developers.phrase.com/en/developer-tools/strings-api-clients These clients are for **Phrase Strings** only. ## phrase-ruby `phrase-ruby` is a Ruby gem that provides interaction with the API. It provides a client for accessing Phrase programmatically within applications. ## phrase-python `phrase-python` is a library for the API written in Python. ## phrase-php `phrase-php` is a library for the API written in PHP. ## phrase-js `phrase-js` is a library for the API written in TypeScript. ## phrase-java `phrase-java` is a library for the API written in Java. ## phrase-go `phrase-go` is a library for the Phrase API written in Golang. # Phrase Strings CLI Source: https://developers.phrase.com/en/developer-tools/strings-cli This tool is for **Phrase Strings** only. The Phrase Strings CLI is a self-contained binary for macOS, Linux, and Windows. It provides command-line access to the full Phrase Strings API and makes it easy to sync locale files between your project and Phrase. ## Installation ```bash Homebrew (macOS) theme={null} brew install phrase-cli ``` ```bash asdf theme={null} asdf plugin add phrase asdf install phrase latest # or a specific version asdf set phrase latest ``` ```bash Docker theme={null} docker run --rm phrase/phrase-cli:latest help ``` For a direct binary, download the archive for your platform from the [phrase-cli releases page](https://github.com/phrase/phrase-cli/releases/latest): ```bash theme={null} curl -L https://github.com/phrase/phrase-cli/releases/latest/download/phrase_linux_amd64.tar.gz | tar xz mv phrase /usr/local/bin/phrase phrase version ``` Download the `.zip` archive from the [releases page](https://github.com/phrase/phrase-cli/releases/latest), extract it, and add the `phrase.exe` binary to a directory on your `PATH`. Verify with `phrase version` from the command prompt. ```bash theme={null} go install github.com/phrase/phrase-cli@latest ``` Requires Go 1.21+. The binary is placed in `$GOPATH/bin`. ## Authentication For details on token types and how to generate them, see [Authentication](/en/api/platform/authentication). The CLI looks for the token in this order: 1. `--access_token` flag 2. `PHRASE_ACCESS_TOKEN` environment variable (recommended) 3. `phrase.access_token` in `.phrase.yml` (discouraged) Avoid putting the token in `.phrase.yml`, especially if the file is committed to a repository: ```bash theme={null} export PHRASE_ACCESS_TOKEN="" ``` You can also pass it directly as a flag: ```bash theme={null} phrase push --access_token $PHRASE_ACCESS_TOKEN ``` ## Quick start ### 1. Initialize your project **Speed up setup with our AI agent skill** The `phrase-strings-config` skill follows the [Agent Skills](https://agentskills.io/home) open format and works with any compatible AI coding agent. It can detect your project's i18n setup and generate `.phrase.yml` automatically. Install it from the [Phrase skills repository](https://github.com/phrase/skills). Run `phrase init` in your project root. The interactive wizard asks for your token, project ID, file format, and locale file path, then creates a `.phrase.yml` config file. ```bash theme={null} phrase init ``` If your account is on the **US datacenter**, pass the host flag: ```bash theme={null} phrase init --host https://api.us.app.phrase.com/v2 ``` You can also skip the wizard entirely with flags: ```bash theme={null} phrase init \ --access_token $PHRASE_ACCESS_TOKEN \ --project_id YOUR_PROJECT_ID \ --file_format yml \ --path 'config/locales/*.yml' ``` ### 2. Upload locale files ```bash theme={null} phrase push ``` Use `--wait` to block until processing completes (recommended in CI): ```bash theme={null} phrase push --wait ``` ### 3. Download locale files ```bash theme={null} phrase pull ``` ## Configuration `phrase init` creates a `.phrase.yml` file in your project root. You can place it in the current working directory, your home directory, or point to it with the `--config` flag or the `PHRASEAPP_CONFIG` environment variable. ### Global settings | Key | Required | Description | | ----------------------- | -------- | ----------------------------------------------------------------------------------------------------- | | `phrase.access_token` | No | Personal access token. Prefer `PHRASE_ACCESS_TOKEN` env var to avoid committing credentials. | | `phrase.project_id` | Yes | Public project ID from project settings → API tab. | | `phrase.file_format` | Yes | Default locale file format (API extension, e.g. `yml`, `json`, `strings`). | | `phrase.host` | No | Override API host, e.g. `https://api.us.app.phrase.com/v2` for US datacenter. | | `phrase.locale_mapping` | No | Maps Phrase locale names to custom locale names, which can be used in file or directory placeholders. | ### Framework examples ```yaml theme={null} phrase: access_token: ACCESS_TOKEN project_id: PROJECT_ID file_format: yml push: sources: - file: ./config/locales/*.yml params: update_translations: true pull: targets: - file: ./config/locales/.yml ``` ```yaml theme={null} phrase: access_token: ACCESS_TOKEN project_id: PROJECT_ID file_format: strings push: sources: - file: ./.lproj/Localizable.strings pull: targets: - file: ./.lproj/Localizable.strings - file: ./.lproj/Localizable.stringsdict params: file_format: stringsdict ``` Android uses non-standard locale directory names. Use `locale_mapping` to map Phrase locale names to Android directory names: ```yaml theme={null} phrase: access_token: ACCESS_TOKEN project_id: PROJECT_ID file_format: xml locale_mapping: en-US: values de-DE: values-de-rDE fr-FR: values-fr push: sources: - file: ./app/src/main/res/values/strings.xml params: locale_id: en-US pull: targets: - file: ./app/src/main/res//strings.xml ``` ```yaml theme={null} phrase: access_token: ACCESS_TOKEN project_id: PROJECT_ID push: sources: - file: apps/web/src/assets/i18n/.json params: file_format: nested_json - file: apps/android/app/src/main/res/values-/strings.xml params: file_format: xml - file: apps/ios/.lproj/Localizable.strings params: file_format: strings pull: targets: - file: apps/web/src/assets/i18n/.json params: file_format: nested_json - file: apps/android/app/src/main/res/values-/strings.xml params: file_format: xml - file: apps/ios/.lproj/Localizable.strings params: file_format: strings ``` ### Full annotated example ```yaml theme={null} phrase: project_id: PROJECT_ID file_format: FORMAT_API_EXTENSION push: sources: - file: ./path/to/file/file.format params: file_format: FORMAT_API_EXTENSION locale_id: LOCALE_ID tags: TAG_1, TAG_2 update_translations: false update_descriptions: false skip_upload_tags: false skip_unverification: false file_encoding: ENCODING autotranslate: false mark_reviewed: false format_options: # format-specific — see Help Center for available options per format pull: targets: - file: ./path/to//file.format params: file_format: FORMAT_API_EXTENSION locale_id: LOCALE_ID tags: TAG_1, TAG_2 include_empty_translations: false exclude_empty_zero_forms: false include_translated_keys: true keep_notranslate_tags: false encoding: ENCODING include_unverified_translations: true use_last_reviewed_version: false fallback_locale_id: LOCALE_ID format_options: # format-specific — see Help Center for available options per format ``` ### Placeholders and globbing Use these placeholders in `file` paths: | Placeholder | Description | | --------------- | -------------------------------------------------------------------------- | | `` | The unique locale name (e.g. `en`, `de-AT`). Preferred for `pull` targets. | | `` | RFC 5646 locale identifier. Not guaranteed unique across locales. | | `` | Groups keys by tag — useful for maintaining original file structures. | Globbing operators work in `push.sources` paths: | Operator | Behavior | | -------- | ---------------------------------------------------- | | `*` | Matches any characters within a single path segment. | | `**` | Matches across directory boundaries (recursive). | ``` ./config/locales/**/*.yml # matches ./config/locales/en.yml and ./config/locales/api/en.yml ``` **Note:** globbing is not supported in `pull.targets` — use explicit paths with placeholders instead. ### Push parameters Key parameters for `push.sources[].params`: | Parameter | Default | Description | | ------------------------- | ------- | ------------------------------------------------------------------------------------------ | | `locale_id` | — | Locale name (e.g. `en-US`) or public locale ID. | | `update_translations` | `false` | Overwrite existing translations with file content. | | `update_descriptions` | `false` | Update key descriptions; empty descriptions overwrite existing. | | `skip_upload_tags` | `false` | Skip creating upload tags. | | `skip_unverification` | `false` | Do not unverify updated translations. | | `tags` | — | Comma-separated tags to apply to new keys. | | `file_format` | — | Override the global file format for this source. | | `file_encoding` | — | Enforce encoding: `UTF-8`, `UTF-16`, `UTF-16BE`, `UTF-16LE`, `ISO-8859-1`. | | `autotranslate` | `false` | Auto-fetch translations for the uploaded locale. | | `mark_reviewed` | `false` | Mark imported translations as reviewed (requires review workflow). | | `update_translation_keys` | `true` | Set to `false` to prevent new keys from being created or existing keys from being updated. | | `translation_key_prefix` | — | Prefix prepended to all key names on push. Use `` as a magic placeholder. | ### Pull parameters Key parameters for `pull.targets[].params`: | Parameter | Default | Description | | --------------------------------- | ------- | --------------------------------------------------------------------- | | `locale_id` | — | Locale name or public locale ID. | | `tags` | — | Comma-separated tags to filter which keys to pull. | | `include_empty_translations` | `false` | Include keys with no translations. | | `include_unverified_translations` | `true` | Set to `false` to exclude unverified translations. | | `use_last_reviewed_version` | `false` | Use the last reviewed translation version (requires review workflow). | | `fallback_locale_id` | — | Fallback locale for missing translations. | | `exclude_empty_zero_forms` | `false` | Exclude zero-form plurals when empty. | | `keep_notranslate_tags` | `false` | Preserve `[NOTRANSLATE]` tags in output. | | `encoding` | — | Enforce encoding on the output file. | | `file_format` | — | Override the global file format for this target. | | `translation_key_prefix` | — | Strip this prefix from key names on pull. | | `filter_by_prefix` | `false` | Only pull keys that match the prefix. | ### Format options Some file formats support additional `format_options` in the `params` section: ```yaml theme={null} push: sources: - file: file.csv params: format_options: column_separator: ";" pull: targets: - file: file.xml params: format_options: convert_placeholder: true ``` For the full list of supported `format_options` per file format, refer to the [Help Center format articles](https://help.phrase.com/help/supported-platforms-and-formats). ## Core commands | Command | Description | | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `phrase init` | Interactive setup — creates `.phrase.yml`. | | `phrase push` | Upload locale files to Phrase. | | `phrase push --wait` | Upload and wait for processing to complete. | | `phrase pull` | Download locale files from Phrase. | | `phrase locales list` | List all locales in the project. | | `phrase uploads cleanup --id ` | Delete keys in the project that were not present in the uploaded file. Run after `phrase push` to remove stale keys. The upload ID is returned by the push command. | | `phrase --help` | Show all options for any command. | | `phrase` | List all available commands. | ## Docker Mount your project directory so the CLI can read `.phrase.yml` and write locale files: ```bash theme={null} docker run --volume $(pwd):/code --workdir /code --rm phrase/phrase-cli:latest pull ``` For interactive commands like `init`, add the `-it` flag: ```bash theme={null} docker run -it --volume $(pwd):/code --workdir /code phrase/phrase-cli:latest init ``` ## Advanced **Monorepos:** Place one `.phrase.yml` in each package and run the CLI from the corresponding folder, or use the `--config` flag to point CI jobs to different config files. **Rate limiting:** When the locale download rate limit is reached, the CLI automatically waits and resumes. You'll see: `rate limit exceeded, download will resume in x seconds`. **Proxy:** Set the `HTTPS_PROXY` environment variable: ```bash theme={null} export HTTPS_PROXY=https://user:password@host:port ``` **Windows shell escaping:** When passing JSON on the command line, use double quotes and escape inner quotes with `\`: ``` phrase locales create --project_id PROJECT_ID --data "{\"name\":\"French\", \"code\":\"fr\"}" --access_token TOKEN ``` ## Git integration When using the CLI with a Git provider (GitHub, GitLab, Bitbucket), ensure the following prerequisites are met in addition to having `.phrase.yml` committed to the repository: * A GitHub access token scoped to the repository (`public_repo` for public repositories). * If SSO is enabled in GitHub, it must also be enabled for the access token. * The `phrase_translations` branch must not be protected. * The repository must not require signed commits. * Read and write access to the repository are required. * Read and write access to the repository are required. * GitLab 9.5 or newer is required for API compatibility. * Ensure `.phrase.yml` contains at least one push source and one pull target with the correct file formats. * Read and write access to the repository are required. * Ensure `.phrase.yml` contains at least one push source and one pull target with the correct file formats. ## GitHub Actions To automate pushes and pulls in CI, use the [Phrase Strings GitHub Action](/en/developer-tools/strings-github-action), which installs the CLI and exposes it to your workflow steps. # Phrase Strings GitHub Action Source: https://developers.phrase.com/en/developer-tools/strings-github-action This tool is for **Phrase Strings** only. The Phrase Strings GitHub Action installs the Phrase CLI in your GitHub Actions workflow, enabling you to automate pushing and pulling translation files as part of your CI/CD pipeline. ## Usage Add the action to your workflow to install the Phrase CLI, then use it to sync your translation files: ```yaml theme={null} steps: - uses: actions/checkout@v4 - uses: phrase/setup-cli@v1 with: version: 2.19.0 - run: phrase pull - run: phrase push --wait env: PHRASE_ACCESS_TOKEN: ${{ secrets.PHRASE_ACCESS_TOKEN }} ``` ## Configuration The action requires a `.phrase.yml` configuration file in your repository. Authentication is handled via the `PHRASE_ACCESS_TOKEN` environment variable, which should be stored as a GitHub Actions secret. # Error Handling and Limits Source: https://developers.phrase.com/en/guides/build-a-tms-plugin/error-handling-and-limits Handle HTTP failures, retries, and Phrase TMS limits safely in plugin integrations. Use this page as your operational reference for runtime failures and platform constraints. ## HTTP error codes | Error code | Meaning | Recommended handling | | ---------- | ------------------------------------- | ---------------------------------------------------------------------------- | | `400` | Invalid request payload or parameters | Validate payload shape, required fields, and enum values before retrying. | | `401` | Authentication failed | Refresh access token, retry once, then surface actionable auth guidance. | | `403` | Authenticated but unauthorized | Check role/permissions in Phrase TMS and account scope. | | `404` | Referenced resource not found | Verify IDs (`projectUid`, `jobUid`, template IDs) and endpoint path version. | | `429` | Rate limit reached | Back off with jitter; reduce poll frequency and burst size. | | `500` | Internal service error | Retry with bounded backoff; capture request context for support escalation. | | `503` | Temporary service unavailability | Retry with bounded backoff; defer non-critical jobs when possible. | ## Rate and async limits Critical constraints to design for: * Phrase TMS documents an API limit of **6,000 requests per minute for logged-in users**. * API request limits require bounded polling and backoff. * Async workflows can queue under load; avoid aggressive status polling. * Webhooks reduce polling load and should be your primary production signal. Use exponential backoff with jitter for retries on `429` and `5xx` responses. Always treat support-doc limits as the source of truth for current values. Reference: * [TMS limits (support)](https://support.phrase.com/hc/en-us/articles/5784117234972-Phrase-TMS-Limits) * [Handling API rate limits](/en/api/tms/latest/handling-api-rate-limits) * [Handling concurrent API limits](/en/api/tms/latest/handling-concurrent-api-limits) ## File handling limits Plan for file import constraints early: * Validate file type and size before upload. * Split very large submissions into smaller batches. * Fail fast with actionable feedback when files are unsupported. Reference: * [File import settings and limits](https://support.phrase.com/hc/en-us/sections/5709618056604-File-Import-Settings) ## Reliability checklist * Implement retry classification: retry only transient errors. * Make create/export operations idempotent. * Track correlation IDs across inbound and outbound calls. * Alert on repeated failure classes and webhook processing lag. * Add fallback polling if webhook events are missed. ## Next steps Apply these safeguards to the full production lifecycle. Build a baseline flow, then harden using this guide. # Full Integration Workflow Source: https://developers.phrase.com/en/guides/build-a-tms-plugin/full-integration-workflow Build a production-ready Phrase TMS plugin with resilient import, monitoring, export, and operations. This guide extends Quick Start with production behavior and optional capabilities. ## At a glance Recommended implementation order: 1. Authentication and token refresh 2. Import (project/job creation) 3. Monitoring (webhook-first) 4. Export and `DELIVERED` status 5. Optional extensions and hardening ## Prerequisites * Completed [Quick Start](/en/guides/build-a-tms-plugin/quick-start). * Phrase TMS project template(s) aligned to your workflow. * Platform and TMS API base URLs for your tenant/region. * Secure storage for API token and runtime secrets. * A callback/webhook endpoint if you use push-based progress handling. If you only need a baseline production flow, implement sections 1-4 first. Sections 5+ are optional hardening and scaling improvements. ## 1) Authentication strategy * Base flow: `POST ${PLATFORM_BASE_URL}/idm/oauth/token` (token exchange). * Include `Authorization: Bearer ` on API requests. * Refresh on expiry and on a single retry after `401`. For production, cache token expiry and centralize token refresh to avoid refresh storms under load. Reference: * [Platform authentication](/en/api/platform/authentication) * [OAuth token endpoint](/en/api/platform/oauth/token-endpoint) ## 2) Import content into TMS ### Required path 1. List templates: `GET /api2/v1/projectTemplates` 2. Create project: `POST /api2/v2/projects/applyTemplate/{templateUid}` 3. Create jobs: `POST /api2/v1/projects/{projectUid}/jobs` Persist `templateUid`, `projectUid`, `job.uid`, and relevant `asyncRequest.id` values. Need payload examples while implementing? Jump to Optional reference: payloads and endpoint map. ### Live preview integration point (optional) If you use live preview, integrate it in this import phase: 1. Upload a preview package after project creation. 2. Store the returned preview package file UID. 3. Include `jobPreviewPackageFileUidRef` when creating the job. See [Live Preview](/en/guides/build-a-tms-plugin/live-preview) for implementation details and failure handling. ### Optional path: expose content listing/download endpoints If your integration uses TMS pull behavior from the third-party system: * Expose a **list endpoint** to return selectable content. * Expose a **download endpoint** to return encoded content for import. * Validate auth and return clear HTTP errors for invalid requests. Keep endpoint responses deterministic. Stable IDs and filenames reduce duplicate imports and debugging complexity. Reference: * [List project templates](/en/api/tms/latest/project-template/list-project-templates) * [Create project from template](/en/api/tms/latest/project/create-project-from-template) * [Create job](/en/api/tms/latest/job/create-job) ### Optional workflow extensions If your lifecycle requires vendor automation and PM workflow support, add these operations after job creation: * Assign providers from template: `POST /api2/v1/projects/{projectUid}/applyTemplate/{templateUid}/assignProviders` * Create analyses by providers: `POST /api2/v1/analyses/byProviders` * Notify assigned users: `POST /api2/v1/projects/{projectUid}/jobs/notifyAssigned` Reference: * [Assign providers from template](/en/api/tms/latest/project/assigns-providers-from-template) * [Create analyses by providers](/en/api/tms/latest/analysis/create-analyses-by-providers) * [Notify assigned users](/en/api/tms/latest/job/notify-assigned-users) ## 3) Monitor job progress Use this priority order: 1. **Webhooks (recommended for production)** 2. **Async request status polling** 3. **Job-part polling fallback** ### Webhooks * Configure webhook subscriptions for job/part/async lifecycle events. * Verify sender token/header. * Store events idempotently, acknowledge quickly, and process asynchronously. ### Async status * Poll `GET /api2/v1/async/{asyncRequestId}` for completion when the workflow uses async endpoints. ### Callback pattern (alternative to polling) Many async endpoints support `callbackUrl`. * Callback payload includes async request metadata and action result. * Callback endpoint should validate sender, persist event, and return `200` quickly. * If callback URL is unreachable, Phrase retries after 2, 4, 8, 16, and 30 minutes (up to 10 failed retries). * Callback delivery is considered successful only when your endpoint returns HTTP `200`. Callback handler pseudocode: ```text theme={null} POST /callbacks/phrase-async verifySignatureOrToken(request) event = parseJson(request.body) saveEventIdempotently(event.asyncRequest.id) enqueueAsyncProcessing(event) return 200 ``` ### Job-part status fallback * Poll `GET /api2/v1/projects/{projectUid}/jobs/{jobUid}/parts` with backoff and jitter. Reference: * [Get asynchronous request](/en/api/tms/latest/async-request/get-asynchronous-request) * Job parts endpoint: `GET /api2/v1/projects/{projectUid}/jobs/{jobUid}/parts` * [Webhooks (support article)](https://support.phrase.com/hc/en-us/articles/5709693398812-Webhooks-TMS) ## Job status reference Use this table to map statuses to plugin behavior. | Status | Typical phase | Meaning | Plugin action | | --------------- | ------------------------- | ------------------------------------------------- | -------------------------------------- | | `NEW` | Creation / pre-assignment | Job exists and is not yet accepted | Keep monitoring and surface as queued | | `ACCEPTED` | Assignment | Provider accepted the job | Continue monitoring workflow progress | | `DECLINED` | Assignment | Provider declined the job | Reassign provider or notify operator | | `COMPLETED` | Completion | Translation workflow is complete | Start export flow | | `DELIVERED` | Post-export | Target content was exported/imported successfully | Treat as terminal success | | `CANCELLED` | Exception | Work was stopped before completion | Treat as terminal failure | | `REJECTED` | Exception / QA | Output was rejected and needs rework | Route for rework, do not deliver | | `JOB_NOT_READY` | Import exception | Job creation/import did not complete correctly | Inspect import errors and retry safely | ## 4) Export translated content ### Pull from TMS via API 1. Start async export: `PUT /api2/v3/projects/{projectUid}/jobs/{jobUid}/targetFile` 2. Wait for completion via webhook/callback/polling. 3. Download file once ready: `GET /api2/v2/projects/{projectUid}/jobs/{jobUid}/downloadTargetFile/{asyncRequestId}` 4. Import result into third-party system. 5. Set terminal status: `POST /api2/v1/projects/{projectUid}/jobs/{jobUid}/setStatus` with `DELIVERED`. ### Push from TMS to your plugin (optional) Expose a secure endpoint to receive translated payloads and run your import mapping there. `asyncRequestId` for download is single-use. Persist and consume it carefully. Reference: * [Download target file async](/en/api/tms/latest/job/download-target-file-async-1) * [Download target file by async request](/en/api/tms/latest/job/download-target-file-based-on-async-request) * [Edit job status](/en/api/tms/latest/job/edit-job-status) ## 5) Continuous updates (optional, high-change workflows) For continuous localization, update source content on existing jobs and re-run the workflow: * Use `POST /api2/v1/projects/{projectUid}/jobs/source` * Monitor completion using callbacks, webhooks, or async polling. * Re-export translated output when updates finish. Reference: * [Update source](/en/api/tms/latest/job/update-source) ## 6) Metadata and reporting Send plugin metadata in the Memsource header payload when creating jobs: ```json theme={null} { "sourceData": { "clientType": "MY_PLUGIN", "clientVersion": "1.2.4", "hostVersion": "4.5.2" } } ``` * `clientType` is required and must be registered with Phrase. * `clientVersion` and `hostVersion` are optional. ## 7) Idempotency implementation guidance Implement idempotency for all create and delivery operations: | Operation | Recommended idempotency key | | --------------------------- | --------------------------------------------- | | Create project | External content batch ID + template ID | | Upload/create job | Source content checksum + locale + project ID | | Start export | Job ID + source revision | | Download/import target file | Async request ID + target system item ID | | Update status (`DELIVERED`) | Job ID + delivered revision | Pattern: 1. Build deterministic operation key before API call. 2. Check/store key in durable storage with operation state. 3. If duplicate key appears, return previously stored result instead of replaying. ## 8) Logging field specification Log these fields for every API call and lifecycle event: | Field | Why it matters | | --------------------- | ------------------------------------------- | | `timestamp` | Event ordering and latency analysis | | `requestId` | Tie plugin logs to HTTP calls | | `correlationId` | Trace a single localization flow end-to-end | | `projectUid` | Project-level troubleshooting | | `jobUid` | Job-level troubleshooting | | `asyncRequestId` | Async lifecycle correlation | | `pluginInstanceId` | Multi-instance debugging | | `endpoint` + `method` | API behavior visibility | | `statusCode` | Error and retry analytics | | `durationMs` | Performance and SLO measurement | ## Plugin variants | Capability | Canonical plugin | Live content plugin | Continuous localization plugin | | ------------------------- | ---------------- | ------------------- | ------------------------------ | | Token exchange + refresh | Must | Must | Must | | Project from template | Must | Must | Must | | Webhooks | Should | Must | Must | | Live preview | Can | Must | Can | | Idempotent source updates | Should | Must | Must | | Advanced observability | Should | Must | Must | ## Operational hardening checklist * Retry transient errors (`429`, `5xx`) with exponential backoff + jitter. * Avoid duplicate create/export actions with idempotency keys or dedupe logic. * Log correlation IDs, project/job IDs, endpoint, status, and latency. * Track success rates and error rates for create/monitor/export operations. * Add alerts for repeated failures and webhook delivery issues. ## Testing expectations * Happy path: create → monitor → export → `DELIVERED`. * Failure path: auth errors, validation errors, rate limits, service errors. * Resilience path: webhook miss + polling fallback. * Update path (if enabled): source updates and repeated export. ## Optional reference: payloads and endpoint map ### Core payload snippets Create project from template request: ```json theme={null} { "name": "Website Translation", "sourceLang": "en", "targetLangs": ["de", "fr"] } ``` Create project from template response (excerpt): ```json theme={null} { "uid": "proj-uid-1", "name": "Website Translation", "status": "NEW", "sourceLang": "en", "targetLangs": ["de", "fr"] } ``` Create job response (excerpt): ```json theme={null} { "jobs": [ { "uid": "job-uid-1", "status": "NEW", "targetLang": "de" } ], "asyncRequest": { "id": "async-req-1", "action": "PRE_ANALYSE" } } ``` Set job status request: ```json theme={null} { "requestedStatus": "DELIVERED", "notifyOwner": true, "propagateStatus": true } ``` ### Endpoint reference glossary | Action | Method | Endpoint | | ----------------------------------------- | ------ | ---------------------------------------------------------------------------------- | | Exchange API token for access token | `POST` | `${PLATFORM_BASE_URL}/idm/oauth/token` | | List project templates | `GET` | `/api2/v1/projectTemplates` | | Create project from template | `POST` | `/api2/v2/projects/applyTemplate/{templateUid}` | | Create job | `POST` | `/api2/v1/projects/{projectUid}/jobs` | | Assign providers from template | `POST` | `/api2/v1/projects/{projectUid}/applyTemplate/{templateUid}/assignProviders` | | Create analyses by providers | `POST` | `/api2/v1/analyses/byProviders` | | Notify assigned users | `POST` | `/api2/v1/projects/{projectUid}/jobs/notifyAssigned` | | Get async request | `GET` | `/api2/v1/async/{asyncRequestId}` | | List job parts | `GET` | `/api2/v1/projects/{projectUid}/jobs/{jobUid}/parts` | | Start async target-file export | `PUT` | `/api2/v3/projects/{projectUid}/jobs/{jobUid}/targetFile` | | Download target file by async request | `GET` | `/api2/v2/projects/{projectUid}/jobs/{jobUid}/downloadTargetFile/{asyncRequestId}` | | Set job status | `POST` | `/api2/v1/projects/{projectUid}/jobs/{jobUid}/setStatus` | | Update source for continuous localization | `POST` | `/api2/v1/projects/{projectUid}/jobs/source` | For complete request/response schemas, use the linked endpoint pages and the [TMS API reference](/en/api/tms/latest/introduction). ## Additional resources * Postman collection for rapid API validation and manual flow testing. * [TMS API reference](/en/api/tms/latest/introduction) for full payload schemas. * [Webhooks support guide](https://support.phrase.com/hc/en-us/articles/5709693398812-Webhooks-TMS) for account-level event setup and retries. ## Next steps Add context-rich in-editor preview behavior. Confirm failure handling and limit-safe behavior. Review endpoint-level request and response details. # Live Preview Source: https://developers.phrase.com/en/guides/build-a-tms-plugin/live-preview Add live preview support so translators can see localized content in context. Live preview helps translators understand context by rendering a visual representation of content in the editor. ## When to use live preview Use live preview when text meaning depends on layout, styling, or surrounding content. Typical cases: * CMS pages with rich formatting. * Product or marketing pages with embedded UI copy. * Content with many short strings where context is critical. ## Prerequisites * A working plugin flow for project/job creation. * Your tenant-specific TMS API base URL (for example `${TMS_BASE_URL}`). * Access to source assets needed for preview rendering. * A strategy for keeping preview assets aligned with source content. ```bash theme={null} TMS_BASE_URL="https:///web" ``` ## Option A: HTML file localization If your source can be represented as HTML, upload HTML directly as the translatable file. Pros: * Simplest setup. * Immediate visual context. Limitations: * Not always feasible for CMS models with complex field structures. * May require custom conversion logic from source model to HTML. ## Option B: Preview package via API If HTML-as-source is not feasible, upload a preview package and reference it during job creation. 1. Build a ZIP package with one HTML entry point plus relative assets. 2. Upload package: `POST /api2/v1/projects/{projectUid}/jobPreviewPackage` 3. Use the returned preview file UID in job creation metadata (`jobPreviewPackageFileUidRef` in Memsource header). ```bash theme={null} curl --request POST "${TMS_BASE_URL}/api2/v1/projects/${PROJECT_UID}/jobPreviewPackage" \ --header "Authorization: Bearer ${ACCESS_TOKEN}" \ --form "file=@preview-package.zip" ``` Reference: * [Upload job preview package](/en/api/tms/latest/project/upload-job-preview-package) * [Create job](/en/api/tms/latest/job/create-job) ## Failure modes and safeguards * Malformed package structure: validate ZIP before upload. * Missing assets or incorrect relative paths: run package integrity checks in CI. * Oversized package: enforce package size limits during build. * Preview mismatch after source updates: re-generate preview package when content schema changes. Keep preview generation deterministic and versioned. It makes regression debugging much faster. ## Next steps Return to the production workflow and integrate preview where needed. Validate limits and failure handling for preview flows. # Introduction Source: https://developers.phrase.com/en/guides/build-a-tms-plugin/overview Understand what a Phrase TMS plugin is, what you will build, and where to start. This guide is for Phrase TMS plugins. It does not cover Phrase Strings, Language AI, or other Phrase products. A TMS plugin is software that lives in a third-party system and connects that system to Phrase TMS. It sends source content for localization, monitors translation progress, and retrieves completed translations back into the source system. New to this flow? Start with Quick Start, then return here for the reference sections. ## What you'll build A production plugin usually follows this lifecycle: 1. Select source content in the third-party system. 2. Authenticate with Phrase Platform and call TMS APIs. 3. Create a project from a project template. 4. Create one or more jobs by uploading source content. 5. Monitor job progress (webhooks, async status, or job-part polling). 6. Export translated files when jobs are complete. 7. Set job status (for example `DELIVERED`) after successful import. ## Choose your path Build a working baseline plugin flow in four steps. Add production behavior, monitoring, and hardening. Handle failures, retries, limits, and operational safeguards. ## Supported file types Common file types used in plugin integrations: | File type | Typical use | | --------------- | ------------------------------------- | | XLIFF 1.2 / 2.0 | Standard localization exchange format | | JSON | Structured application or CMS content | | XML | Structured content and metadata | | Markdown | Documentation and content workflows | | Plain text | Simple non-structured content | For import-specific parsing behavior, see [file import settings](https://support.phrase.com/hc/en-us/sections/5709618056604-File-Import-Settings). ## Key concepts | Term | Definition | | ------------------- | ----------------------------------------------------------------------------------------- | | Project template | Reusable configuration used to create projects with standard settings and workflow steps. | | Project | Container for related translation jobs. | | Job | A translation unit for one file and one target language. | | Workflow | Ordered translation/review steps that jobs move through. | | `asyncRequest` | Identifier for asynchronous API operations that complete later. | | Locale | Source or target language/region identifier used in localization. | | Machine translation | Automated translation used in workflow steps, often combined with human review. | | Markup language | Structured formats (for example HTML/XML) where text and tags must be handled safely. | | Segmentation | Splitting content into translatable segments used for progress and QA operations. | | Translation memory | Reusable translation database used to improve consistency and speed. | ## Core objects and data models (minimum) Use these core object shapes in your plugin data layer. | Object | Purpose | Key fields to persist | | ---------------- | -------------------------------------- | ---------------------------------------------------------- | | Project Template | Defines default project configuration | `uid`, `templateName`, `sourceLang`, `targetLangs[]` | | Project | Container for jobs | `uid`, `name`, `status`, `sourceLang`, `targetLangs[]` | | Job | Translation unit for a target language | `uid`, `status`, `targetLang`, `workflowLevel`, `filename` | | Async Request | Tracks asynchronous work | `id`, `action`, `dateCreated` | | Async Response | Completion payload for async work | `errorCode`, `errorDesc`, `warnings[]` | Representative JSON shapes: ```json theme={null} { "projectTemplate": { "uid": "pt-uid-1", "templateName": "Website Default", "sourceLang": "en", "targetLangs": ["de", "fr"] }, "project": { "uid": "proj-uid-1", "name": "Website Translation", "status": "NEW" }, "job": { "uid": "job-uid-1", "status": "NEW", "targetLang": "de", "workflowLevel": 1 }, "asyncRequest": { "id": "async-req-1", "action": "PRE_ANALYSE" }, "asyncResponse": { "errorCode": null, "errorDesc": null } } ``` ## Next steps Build the minimum end-to-end flow first. Expand to a production-ready integration. Add editor preview capabilities for translators. # Quick Start Source: https://developers.phrase.com/en/guides/build-a-tms-plugin/quick-start Build your first Phrase TMS plugin flow in four practical steps. This quick start gives you the minimum end-to-end plugin flow: authenticate, create project and jobs, monitor progress, and download translated output. ## At a glance You will implement this sequence: 1. Authenticate 2. Create project and job 3. Monitor progress 4. Export and set `DELIVERED` ## Prerequisites * Phrase account with TMS access. * Phrase Platform API token. * Platform base URL and TMS API base URL for your tenant/region. * At least one TMS project template available in your org. * A sample source file to upload. * Basic REST API familiarity. Set base URLs once and reuse them in examples: ```bash theme={null} PLATFORM_BASE_URL="https://.phrase.com" TMS_BASE_URL="https:///web" ``` Do not hardcode EU endpoints unless your tenant is on EU infrastructure. ## Step 1: Authenticate Exchange your API token for a short-lived access token and send it as `Authorization: Bearer `. ```bash theme={null} curl --request POST "${PLATFORM_BASE_URL}/idm/oauth/token" \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \ --data-urlencode 'subject_token=YOUR_API_TOKEN' ``` Use this token exchange flow for all subsequent API calls. Refresh before expiry or on a single retry after `401`. See [Platform authentication](/en/api/platform/authentication) and [OAuth token endpoint](/en/api/platform/oauth/token-endpoint). ## Step 2: Create a project and job 1. List project templates: `GET /api2/v1/projectTemplates` 2. Create project from template: `POST /api2/v2/projects/applyTemplate/{templateUid}` 3. Create job in project: `POST /api2/v1/projects/{projectUid}/jobs` ```bash theme={null} curl --request POST "${TMS_BASE_URL}/api2/v2/projects/applyTemplate/${TEMPLATE_UID}" \ --header "Authorization: Bearer ${ACCESS_TOKEN}" \ --header 'Content-Type: application/json' \ --data '{"name":"My Plugin Quick Start Project"}' ``` Persist `projectUid`, `job.uid`, and any returned `asyncRequest.id`. You need these IDs later. Reference docs: * [List project templates](/en/api/tms/latest/project-template/list-project-templates) * [Create project from template](/en/api/tms/latest/project/create-project-from-template) * [Create job](/en/api/tms/latest/job/create-job) ## Step 3: Monitor progress Use one of these methods: * Simple start: poll `GET /api2/v1/projects/{projectUid}/jobs/{jobUid}/parts` * Async operation status: poll `GET /api2/v1/async/{asyncRequestId}` when relevant * Production approach: webhook events with polling fallback ```bash theme={null} curl --request GET "${TMS_BASE_URL}/api2/v1/projects/${PROJECT_UID}/jobs/${JOB_UID}/parts" \ --header "Authorization: Bearer ${ACCESS_TOKEN}" ``` Treat terminal failure statuses (`CANCELLED`, `REJECTED`) as non-deliverable outcomes. ## Step 4: Export and mark delivered 1. Start async download: `PUT /api2/v3/projects/{projectUid}/jobs/{jobUid}/targetFile` 2. Wait until async request is complete. 3. Download target file: `GET /api2/v2/projects/{projectUid}/jobs/{jobUid}/downloadTargetFile/{asyncRequestId}` 4. Mark delivered: `POST /api2/v1/projects/{projectUid}/jobs/{jobUid}/setStatus` with `requestedStatus: DELIVERED` ```json theme={null} { "requestedStatus": "DELIVERED", "notifyOwner": true, "propagateStatus": true } ``` Reference docs: * [Download target file async](/en/api/tms/latest/job/download-target-file-async-1) * [Download target file by async request](/en/api/tms/latest/job/download-target-file-based-on-async-request) * [Edit job status](/en/api/tms/latest/job/edit-job-status) ## Optional: implementation patterns (pseudocode) Use these patterns when moving from sample calls to production code. You can skip this section for a first pass. ### Auth caching and one-time `401` retry ```text theme={null} CACHE = { token: null, expiresAt: 0 } function getAccessToken(): if CACHE.token exists and now < CACHE.expiresAt - safetyWindow: return CACHE.token tokenResponse = POST ${PLATFORM_BASE_URL}/idm/oauth/token CACHE.token = tokenResponse.access_token CACHE.expiresAt = now + tokenResponse.expires_in return CACHE.token function authRequest(method, url, body): token = getAccessToken() response = HTTP(method, url, header={"Authorization": "Bearer " + token}, body=body) if response.status == 401: CACHE.token = null token = getAccessToken() response = HTTP(method, url, header={"Authorization": "Bearer " + token}, body=body) return response ``` ### Async polling with bounded backoff ```text theme={null} function waitForAsync(asyncRequestId, timeout): delay = 2s until timeout: status = GET /api2/v1/async/{asyncRequestId} if status.asyncResponse exists: if status.asyncResponse.errorCode exists: fail(status.asyncResponse) return status.asyncResponse sleep(delay + jitter) delay = min(delay * 2, 60s) ``` ### Export completion flow ```text theme={null} start = PUT /api2/v3/projects/{projectUid}/jobs/{jobUid}/targetFile waitForAsync(start.asyncRequest.id) file = GET /api2/v2/projects/{projectUid}/jobs/{jobUid}/downloadTargetFile/{start.asyncRequest.id} importToSourceSystem(file) POST /api2/v1/projects/{projectUid}/jobs/{jobUid}/setStatus {"requestedStatus":"DELIVERED"} ``` ## Next steps Add production-grade behaviors and resilience. Add contextual preview support for translators. Harden retries, limits, and failure behavior. # Translate multiple segments asynchronously Source: https://developers.phrase.com/en/guides/byo-engine/asynchronous-translation/translate-multiple-segments-asynchronously /openapi/phrase-byo-mt.json post /translateAsync # Translate multiple segments asynchronously - get translated segments Source: https://developers.phrase.com/en/guides/byo-engine/asynchronous-translation/translate-multiple-segments-asynchronously--get-translated-segments /openapi/phrase-byo-mt.json get /translateAsyncResult/{id} # Translate multiple segments asynchronously - status polling Source: https://developers.phrase.com/en/guides/byo-engine/asynchronous-translation/translate-multiple-segments-asynchronously--status-polling /openapi/phrase-byo-mt.json get /translateAsyncStatus/{id} # Get engine status Source: https://developers.phrase.com/en/guides/byo-engine/engine-status/get-engine-status /openapi/phrase-byo-mt.json post /status # Introduction Source: https://developers.phrase.com/en/guides/byo-engine/introduction ## Phrase BYO Engine API Machine translation powered by [Phrase](https://phrase.com/) allows the translation of content using a unique AI powered feature to pick the best available translation engine for that content. By implementing the following API it is possible to integrate custom machine translation engine directly into [Phrase Language AI](https://support.phrase.com/hc/en-us/articles/5709660879516-Phrase-Language-AI-TMS). A minimal BYO Engine machine translation API specification. It supports the following operations and features: * [supported languages](/en/guides/byo-engine/supported-languages/get-supported-language-pairs) * [engine status](/en/guides/byo-engine/engine-status/get-engine-status) * multi-segment translation operations * [synchronous translation](/en/guides/byo-engine/synchronous-translation/translate-multiple-segments) * [asynchronous translation](/en/guides/byo-engine/asynchronous-translation/translate-multiple-segments-asynchronously) * [with glossaries](/en/guides/byo-engine/synchronous-translation/translate-multiple-segments#body-glossary) * applies to both synchronous and asynchronous endpoints * [with custom metadata](/en/guides/byo-engine/synchronous-translation/translate-multiple-segments#body-metadata) * applies to both synchronous and asynchronous endpoints ## Dynamic Metadata Phrase automatically resolves the following placeholders in request-level metadata values before sending them to the engine: | Placeholder | Resolved value | | ------------------------ | ----------------------- | | `{project_uid}` | TMS project UID | | `{job_uid}` | TMS job UID | | `{idm_organization_uid}` | Phrase organization UID | These can be used to pass contextual information about the translation job to your engine without any additional integration work. ## Authentication For authentication either the [OAuth client credentials flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) or an API token can be leveraged. ## Demo Implementation A reference implementation of the adapter is available [here](https://github.com/phrase/custom.adapter). It demonstrates a basic integration and includes additional guidance. ## Technical Notes * Implement your adapter in accordance with the [OpenAPI schema](https://developers.phrase.com/public/assets/openapi/phrase-byo-mt.yaml). * In general, but especially for the asynchronous endpoints, **ensure thread safety and proper concurrency handling** to prevent race conditions where concurrent requests could overwrite each other's data. ### Stability and Performance Recommendations * **DNS Infrastructure & Routing:** Ensure DNS resolution is stable and all entries are correctly configured. Misconfigurations or propagation delays can result in intermittent resolution failures, elevated latency, or request timeouts. * **Application & Proxy Server Tuning (e.g., Nginx):** Optimize your proxy or gateway servers for high-concurrency traffic. Review keep-alive settings and worker process limits to avoid TCP connection resets or dropped requests under load. * **Load & Concurrency Testing:** Perform synthetic load tests from external endpoints before going to production. Validate your adapter against a sustained concurrency of 100–200 requests per second (RPS) to confirm that performance remains linear and stable. *** # Get supported language pairs Source: https://developers.phrase.com/en/guides/byo-engine/supported-languages/get-supported-language-pairs /openapi/phrase-byo-mt.json post /languages # Translate multiple segments Source: https://developers.phrase.com/en/guides/byo-engine/synchronous-translation/translate-multiple-segments /openapi/phrase-byo-mt.json post /translate # Creating an APC Source: https://developers.phrase.com/en/guides/managing-automated-project-creation/creating-an-apc Every field POST /api2/v3/automatedProjects needs, where its options come from, and the order the TMS UI itself resolves them in. Creating an APC setting has more required fields than a typical create call, and several of them have a real, discoverable set of valid options — don't ask for these blind, and don't guess a shape for the ones with no dedicated list endpoint either. ## 1. Confirm the connector Every APC belongs to an existing connector. List your connectors (`GET /api2/v1/connectors`) and confirm the one to use before anything else — never guess or fabricate a connector identifier. See [Managing TMS Connectors](/en/guides/managing-connectors/overview) if you don't have one set up yet. ## 2. Pick a project template — before languages, not after ```bash theme={null} GET /api2/v1/projectTemplates ``` Lists your available templates by name and `uid`. Resolve this **before** asking about languages: a project template's detail response carries the source/target languages it was created with. ```bash theme={null} GET /api2/v1/projectTemplates/{projectTemplateUid} ``` `sourceLang` and `targetLangs` on this response are inherited from the project the template was originally created from — this is exactly why the TMS UI only shows you language options once you've picked a template. Present those as your language choices; only fall back to the full, unscoped `GET /api2/v1/languages` list if the chosen template happens to have no languages set. The resolved target languages go into the create payload's `selectedTargetLangs` field (a required array of language codes) — the field name doesn't otherwise appear anywhere in this resolution step, so don't guess a different name (e.g. `targetLangs`) when building the request. ## 3. Browse the remote folder — don't ask for a path ```bash theme={null} GET /api2/v1/connectors/{connectorId}/folders GET /api2/v1/connectors/{connectorId}/folders/{encodedFolder} ``` Lists the connector's root folders, or a subfolder if you pass one. Browse and present the real folders/projects found — don't ask the user to type a path from memory, and don't guess a template like `/project/{id}` or `/space/...`. For a `PHRASE`-type connector (TMS ↔ Phrase Strings), the browsable structure returned here is Strings projects/spaces rather than a literal filesystem path — present the real project/space names the endpoint returns. `PHRASE` is a real, valid connector type; if a browse call fails for a specific connector, that's an operation-specific failure, not evidence the connector or its type doesn't exist. Once a folder is chosen, translate it into the create payload's `monitoredFolders[]` entry: `remoteFolder` (the folder path), `folderNames` (its path segments as a list), and `humanReadableFolderPath` — derive these from the browsed result, don't fabricate them from the folder name alone. `monitoredFolders[].localToken` is the connector's own `localToken` field (from its list/get response — not its `id`), which the backend needs to resolve which remote storage to read. If a connector type doesn't support folder browsing at all, say so and let the user pick the folder in the TMS UI instead, then continue the rest of the flow normally. ## 4. Schedule (`frequency.frequencyOption`) or webhook trigger (`webhookToken`) The schema requires **either** `frequency` **or** `webhookToken`, not both — ask the user which triggering model they want before assuming a schedule is the only option. For a schedule, there's no list endpoint — it's a genuine question — but the valid `frequencyOption` values come straight from the create endpoint's schema, so offer them as named options rather than an open "how often?": * `WEEKLY_FIXED_TIMES` — runs at specific times on specific days of the week * `HOUR_TIME_RANGE` — runs every N hours (`range`) * `MINUTE_TIME_RANGE` — runs every N minutes (`range`) * `MONTHLY_FIXED_TIMES` — runs at specific times on specific days of the month Each option has its own sub-fields (e.g. `weeklyFixedTimes[]`, `monthlyFixedTimes[]`) — check the full request schema for the shape once you know which one applies. For a webhook-triggered setup instead, `webhookToken` is a plain string field — the automated project creation runs when that webhook is called, rather than on a schedule. ## 5. Translation-export rule At least one `translationExports[]` entry is required. Again, no list endpoint, but the schema constrains the valid values: * `exportFrom.type`: `FINAL_WORKFLOW_STEP` or `WORKFLOW_STEP` (with `workflowStep` number, if the latter) * `exportWhen.exportTrigger`: `SELECTED_WORKFLOW_STEP_COMPLETED`, `FINAL_WORKFLOW_STEP_COMPLETED`, or `PROJECT_COMPLETED` A reasonable default to suggest is exporting when the final workflow step completes — but present the actual options rather than assuming silently, and don't invent a webhook-based trigger; it isn't part of this schema. ## 6. Continuous vs. one-off projects `continuousProject: true` imports files into a single, continuously-updated project instead of creating a new project on every run. This is a yes/no the user needs to decide — there's no discoverable default. ## Putting it together Resolve every field above — connector, template (and its languages), folder, schedule, export rule — before presenting a single confirmation message with real values for all of them. Don't send the user a list of field names to fill in one at a time, and don't offer to fetch a list "if you'd like" — fetch it, then ask. # Introduction Source: https://developers.phrase.com/en/guides/managing-automated-project-creation/overview Understand what Automated Project Creation (APC) is, how it relates to connectors, and the endpoints that manage it. This guide is about **Automated Project Creation (APC)** — a TMS feature that watches a connector's remote storage and automatically creates translation projects when new files show up. It assumes you already have a working connector; see [Managing TMS Connectors](/en/guides/managing-connectors/overview) if you don't. ## What APC does Automated Project Creation lets an already-configured connector do more than move files on request — it watches one or more folders (or, for connector types without a real filesystem, the equivalent browsable structure) on a schedule, and automatically creates a new translation project (or updates an existing continuous one) whenever it finds new or changed content. APC always belongs to exactly one connector. There's no such thing as an APC setting that isn't tied to a connector — if you don't have one set up yet, create it first (see [Managing TMS Connectors](/en/guides/managing-connectors/overview)). ## Not the standalone Connectors API The same product-boundary confusion that applies to connector lifecycle applies here too: the standalone [Connectors API](/en/api/connectors/introduction) only moves file content through an already-configured connector — it has no concept of automated project creation. APC lifecycle lives entirely on the TMS API. ## The APC lifecycle endpoints | Method & path | Purpose | | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `GET /api2/v1/automatedProjects` | List your APC settings (paginated — see below) | | `POST /api2/v3/automatedProjects` | Create an APC setting | | `GET /api2/v3/automatedProjects/{settingsId}` | View an APC setting's full configuration | | `PUT /api2/v3/automatedProjects/{settingsId}` | Update an APC setting (full replace — see [Troubleshooting](/en/guides/managing-automated-project-creation/troubleshooting)) | | `DELETE /api2/v1/automatedProjects/{settingsId}` | Delete one APC setting | | `DELETE /api2/v1/automatedProjects/batch` | Delete several APC settings by id in one call | | `GET /api2/v1/automatedProjects/{settingsId}/running` | Check whether it's currently running | | `GET /api2/v1/automatedProjects/{settingsId}/status` | Check its last-run status | | `GET .../monitoredFolder/{folder}/connectors/{connectorId}/folders/{folder}` | Browse an existing APC's monitored folder contents | APC settings are organization-scoped — they're addressed directly by their own `settingsId`, never nested under a project. Don't construct a project-nested path for them. `GET /api2/v1/automatedProjects` returns up to 50 results per call (`pageSize`, 0-indexed `pageNumber`). Check `totalElements`/`totalPages` on the first response and page through all of them before treating the result as complete — a large organization can easily have well over 50 APC settings. ## Choose your path Walk through every field the create call needs — project template, target languages, monitored folder, schedule, and translation-export rule. The full-replace PUT trap, listing gotchas, and per-connector-type quirks. # Troubleshooting Source: https://developers.phrase.com/en/guides/managing-automated-project-creation/troubleshooting The full-replace PUT trap, listing gotchas, and per-connector-type quirks for Automated Project Creation. ## Enabling, disabling, or editing silently doesn't stick There is no dedicated enable/disable or partial-update endpoint for APC. `GET .../running` and `GET .../status` are read-only state checks — they can't be used to change anything. The **only** write path for any change, including just flipping `active`, is: ```bash theme={null} PUT /api2/v3/automatedProjects/{settingsId} ``` This is a **full replace** — it requires `frequency`, `id`, `monitoredFolders`, and `name` in the body regardless of what you're actually changing. Sending a body with only the field you're changing (e.g. just `{"active": true}`) can be accepted by the API without an error, but doesn't actually persist the change — a follow-up `GET` will show the setting reverted to its previous state. The response echoing back your intended value is **not** proof the change was saved. To make any change safely: 1. `GET /api2/v3/automatedProjects/{settingsId}` first — **not** the `GET /api2/v1/automatedProjects` list result, which is a flatter shape (`connectorId`/`connectorName` instead of nested `monitoredFolders`) and is missing fields the `v3` `PUT` requires. 2. Take that full object, change only the field(s) you actually want to change, and send the **complete** object back. 3. `GET` the same `settingsId` again afterward and confirm the field actually changed before considering the update successful. ## Listing has no owner/creator field Neither the list nor the single-get response for an APC setting exposes who created it. There's no way to filter "my APC settings" — either server-side or by post-processing the response, since the field simply isn't there. If you need to narrow a large list down, filter by connector, by active/inactive state, or by name instead. ## Listing is paginated `GET /api2/v1/automatedProjects` returns at most 50 results per call (`pageSize`, default and max 50; `pageNumber`, 0-indexed). Check `totalElements`/`totalPages` on the first response and keep paging until you've collected everything — reporting the first page's contents as "the full list" is wrong the moment your organization has more than 50 APC settings. ## `PHRASE` connectors are a valid, real connector type `PHRASE` (the connector that connects TMS to Phrase Strings) is a documented `ConnectorType` enum value, same as `BOX`, `GIT`, `CONTENTFUL`, `MARKETO`, or `OPTIMIZELY` — it's a legitimate choice for an APC's underlying connector. If browsing its folders behaves differently than a filesystem-backed connector (see [Creating an APC](/en/guides/managing-automated-project-creation/creating-an-apc)), that's a property of that connector type, not a sign it doesn't exist or isn't supported. ## Deletion `DELETE /api2/v1/automatedProjects/{settingsId}` deletes one setting; `DELETE /api2/v1/automatedProjects/batch` deletes several by id in a single call. Both are permanent — confirm the exact setting(s) before calling either. # OAuth Connector Setup Source: https://developers.phrase.com/en/guides/managing-connectors/oauth-setup Authorize and create OAuth-based TMS connectors (Google Drive, GitHub, Box, Salesforce, and others). Many connector types authenticate via OAuth 2.0 rather than a plain username/password or API key. Setting one up requires walking the end user through a browser-based authorization step before the connector can be created. ## Which connector types use OAuth These types require the authorization flow described below: `GITHUB`, `GITHUB2`, `BITBUCKET`, `BOX`, `ONEDRIVE`, `SHAREPOINT`, `GOOGLE`, `GOOGLE_DRIVE2`, `SALESFORCE`, `VERBIS`, `HUBSPOT`, `ZENDESK`, `CONTENTFUL`, `CONTENTFULENTRYLEVEL`, `CONTENTFUL2`. Some similarly-named types are **not** OAuth-based, and calling the authorization endpoint for them will fail: `GITLAB` and `BITBUCKETSERVER` use a plain host+token (personal access token), `MARKETO` uses an API key/secret pair, and `OPTIMIZELY`/`TRIDION` use OIDC client-credentials with no user redirect at all. `PHRASE` (the connector to Phrase Strings) also isn't OAuth, despite having a `code`-shaped field — see the note at the end of this page. ## The authorization flow ### 1. Get a one-time state token ```bash theme={null} POST /api2/v1/connectors/connectorAuthData ``` This returns a one-time `state` token that correlates your authorization attempt with the eventual callback. ### 2. Get the authorization page URL ```bash theme={null} GET /api2/v1/connectorAuthPage/{type}?hostPrefix={tmsHost} ``` * `{type}` must be the **exact same** `ConnectorType` enum value you'll use to create the connector — not an abbreviation, and not a differently-cased variant. This matters more than it sounds: for example, Google Drive's correct type is `GOOGLE_DRIVE2`. `GOOGLE_DRIVE` doesn't exist as a type, and `GOOGLE` is a *different*, separate connector type — calling this endpoint with `GOOGLE` returns `200` successfully, but authorizes against the wrong provider configuration, and will break connector creation later. A `400` response here almost always means the type value is wrong, not that a parameter is missing. * `hostPrefix` should be the bare TMS hostname (host only, no scheme or path — e.g. `qa.memsource.com`). **The returned `url` field is a template, not a ready-to-use link.** It contains literal placeholder text — `{state}` and `{redirectUri}` — that you must substitute yourself before sending it anywhere. The backend does not fill these in. Substitute: * `{state}` → the token from step 1. * `{redirectUri}` → `/web/connector/receiveConnectorAuthCode` (this exact path is correct for every provider — don't vary it, and don't guess an alternative like `/tms/...`). If the third-party provider rejects the resulting link with something like "redirect\_uri is not associated with this application," that means this fixed path doesn't match what's registered for that specific OAuth app — that's a configuration question for whoever manages the app's registered callback URLs, not something to work around by guessing a different path. Only send the user a **fully substituted** URL — never one still containing literal `{state}` or `{redirectUri}` text, since the provider will reject it outright. ### 3. Let the user authorize, then poll for the code Once the user completes the provider's sign-in and consent screen, their browser is redirected to the callback URL above with the real authorization `code` attached — but that callback page auto-submits the code server-side and the URL reverts within seconds, too fast to copy by hand. Instead, poll for it: ```bash theme={null} GET /api2/v1/connectors/connectorAuthCode/{code} ``` Despite the path parameter's name, pass the **state** token from step 1 here, not a code you don't have yet — the parameter is misleadingly named. Poll every few seconds until the response contains a populated `code` (not `null`). If the user reports landing on the callback page with no code and no visible error, this is usually a stale or reused `state` token — restart from step 1 with a fresh one. ### 4. Create the connector Create the connector using the code you polled for, following the type-specific fields documented in the [API reference](/en/api/tms/latest/introduction). ## GitHub Apps (`GITHUB2`) need one extra step `GITHUB2` uses GitHub's newer "GitHub App" model rather than a classic OAuth App, which has two extra requirements beyond the flow above: **The Phrase GitHub App must be installed** on the user's GitHub account or organization — OAuth sign-in alone does not install it. Direct users to install it here, ideally alongside the authorization link rather than only after a failure: ``` https://github.com/apps/phrase-github-integrations-app/installations/new ``` **An extra API call is required** before creating the connector, since its payload needs `login` and `tempLocalToken` fields that the standard code exchange doesn't provide: ```bash theme={null} POST /api2/v3/connectors/github2/connect { "code": "...", "redirectUri": "..." } ``` This returns `{ "localToken": "...", "logins": [...] }`. If `logins` has more than one entry, ask the user which GitHub org/account to connect. Then create the connector with: ```json theme={null} { "type": "GITHUB2", "login": "", "tempLocalToken": "" } ``` Don't pass `code`/`redirectUri` directly to the create call for `GITHUB2` — that request shape is for classic `GITHUB` connectors only. ## Google Drive (`GOOGLE`, `GOOGLE_DRIVE2`) need `oauthClientId` too Both types' create payload requires an `oauthClientId` field in addition to `code`+`redirectUri` — the create request fails without it. You don't need to look this up separately or ask the user for it: the same `connectorAuthPage` call from step 2 above already returned an `oauthClientId` field in its response. Reuse that exact value verbatim in the create call. ## Salesforce (`SALESFORCE`) specifics Salesforce differs from every other OAuth type in two ways that aren't obvious from the generic flow above. ### `hostPrefix` means something different for Salesforce For every other type, `hostPrefix` in step 2 is just the TMS hostname, used to build the TMS-side redirect URI. For Salesforce, `connectorAuthPage` instead builds the third-party authorize URL as `https://{hostPrefix}.salesforce.com/services/oauth2/authorize?...` — `hostPrefix` here is **Salesforce's own login-domain prefix**, not the TMS host. Passing the TMS host (e.g. `qa.memsource.com`) produces a real-looking but wrong domain (`qa.memsource.com.salesforce.com`) — a browser certificate error, not a real Salesforce host. Omitting it produces a broken empty-prefix URL (`https://.salesforce.com/...`). Salesforce has required "My Domain" (`*.my.salesforce.com`) for all orgs for years, including every Developer Edition org (any domain ending `-dev-ed`). If the org identifier you have doesn't already end in `.my` (e.g. `d3x000002kko8uao-dev-ed`), append it yourself (`d3x000002kko8uao-dev-ed.my`) rather than sending it as-is — only use a bare `login`/`test` prefix (no `.my`) if you've confirmed the org still uses the legacy non-My-Domain login page. Sending the identifier without `.my` produces a `net::ERR_CERT_COMMON_NAME_INVALID` browser error. ### `salesforcePublishStrategyType` is required The create call fails without this field. Its only valid values are: * `PUBLISH` — translated content is published live immediately * `DRAFT` — translated content is saved as a draft, not published live * `SAME_AS_LATEST_TRANSLATION` — mirrors the publish state of the most recent translation No other values exist — plausible-sounding names like `KNOWLEDGE` or `SALESFORCE_KNOWLEDGE` are not valid and will be rejected. If you're unsure which to pick, `PUBLISH` is the safest default, but confirm it against your own publishing requirements. Collect this value upfront, alongside the other connector fields, rather than as a follow-up after a failed create attempt — each OAuth authorization code from step 3 is single-use, so a failed create call burns it and requires a full re-authorization for the next attempt. ## `PHRASE` connectors are the exception The `PHRASE` connector type (which connects TMS to Phrase Strings, not another TMS instance or a third party) has a `code`-shaped field but is **not** part of this OAuth flow — it has no third-party OAuth provider registered, and calling `connectorAuthPage` for it returns an empty `url` by design. Its authorization is instead resolved server-side from your own authenticated identity. Attempt creation directly with the connector's base fields plus its Strings-specific fields (`phraseTmsOrganizationId`/`phraseTmsOrganizationName`). # Introduction Source: https://developers.phrase.com/en/guides/managing-connectors/overview Understand the difference between the Connectors API and TMS connector management, and what you can do with each. This guide is about **managing TMS connectors** — connecting Phrase TMS to third-party systems like Google Drive, GitHub, Amazon S3, WordPress, Marketo, and others. It does not cover building a new connector type from scratch; see [Build a TMS Plugin](/en/guides/build-a-tms-plugin/overview) for that. ## Two different APIs, easy to confuse Phrase has two separate API surfaces that both use the word "connector," and it's easy to reach for the wrong one: * **The [Connectors API](/en/api/connectors/introduction)** only moves file content through a connector that has *already been set up* — listing, uploading, downloading, and converting files inside a connector's remote storage. It has no endpoints to create, edit, or delete a connector itself. * **The TMS API** (this guide) owns the connector's actual lifecycle — creating a new connector, listing your existing ones, viewing or editing a connector's configuration, deleting it, and checking its sync status. This is where you go to set up a new Google Drive, GitHub, Amazon S3, WordPress, or Marketo connector. If you're trying to programmatically create or configure a connector and you're looking at the Connectors API, you're in the wrong place — come back here instead. ## What you'll build A typical connector setup flow looks like this: 1. Confirm the connector doesn't already exist (list existing connectors and check by name/type — avoid creating duplicates). 2. For OAuth-based connector types (Google Drive, GitHub, Box, Salesforce, and others — see [OAuth Connector Setup](/en/guides/managing-connectors/oauth-setup)), walk the user through authorizing access to the third-party account. 3. Create the connector with the fields that type requires. 4. Check the connection status, and fix credentials if it's rejected. 5. Optionally, monitor sync status and browse what the connector has picked up. ## Choose your path Walk through the authorization-code flow required for Google Drive, GitHub, Box, Salesforce, and other OAuth-based connector types. Diagnose access-denied errors, per-connector-type field quirks, and common setup mistakes. ## The connector lifecycle endpoints All connector lifecycle operations live under `/api2/v1/connectors` on the TMS API: | Method & path | Purpose | | ----------------------------------------------- | ------------------------------------------- | | `GET /api2/v1/connectors` | List your connectors | | `POST /api2/v1/connectors` | Create a connector | | `GET /api2/v1/connectors/{connectorId}` | View a connector's configuration | | `PATCH /api2/v1/connectors/{connectorId}` | Edit a connector's configuration | | `DELETE /api2/v1/connectors/{connectorId}` | Delete a connector | | `GET /api2/v1/connectorAsyncTasks` | Check background sync task status | | `GET /api2/v1/connectors/{connectorId}/folders` | Browse what a connector has actually synced | Before creating a connector, list your existing connectors and check for one with a matching name/type — this avoids accidentally creating duplicates if a previous attempt errored or its result was unclear. Once a connector is created, keep a reference to its `uid` — you'll need it to view, edit, delete, or check the status of that connector later, and it's what you'd use to link directly to the connector's page in the TMS UI (`/tms/connectors/edit/{uid}`). `PATCH /api2/v1/connectors/{connectorId}` requires **both** `name` and `type` in the request body, even if you're only changing one field (e.g. a pure rename). Sending just the changed field (e.g. `{"name": "..."}` alone) is rejected with a `400` ("Cannot parse the JSON request"). Read the connector's current `type` from a prior `GET` before editing it. A connector being successfully **created** is a different thing from its connection being successfully **tested**. Creating or editing a connector does **not** automatically verify its credentials, except for `MAGENTO` and `TYPO3` connector types, which always run a live connection test. For every other type, pass `connectionTest=true` as a query parameter on `POST`/`PATCH` to run one explicitly — otherwise a connector with entirely wrong credentials can be created successfully and only fail later. If a connection test reports an error status (e.g. `GENERAL_ERROR`, `UNAUTHORIZED`), the connector object still exists — you'll usually need to go fix its credentials rather than starting over. # Troubleshooting Source: https://developers.phrase.com/en/guides/managing-connectors/troubleshooting Common connector setup errors, per-connector-type field quirks, and how to diagnose access-denied responses. ## Access-denied (403) on connector creation A `403`/access-denied response when creating a connector has two unrelated causes that share the same generic exception — always read the exact error message text, since that's the only way to tell them apart. ### 1. Role and access rights Creating a connector requires the **ADMIN** or **PROJECT\_MANAGER** role, *and* a separate access right called **"Modify global server settings"**. Having the ADMIN role does not guarantee this right is enabled — it's an independent per-account setting. If your error message is a generic access-denied with no further detail, check this first. ### 2. Per-connector-type subscription entitlement Some connector types are gated behind their own subscription add-on, independent of your role or access rights: `AEM_PLUGIN`, `CONTENTFUL`, `HUBSPOT`, `OPTIMIZELY`, `TRIDION`, `KENTICO_KONTENT`, `BRAZE_MULTILANG`, `CONTENTSTACK`, `MARKETO`, and `ZENDESK` each require a separate Phrase subscription add-on. If the error message literally says something like **"`` is not enabled"**, this is not a permissions problem at all — your organization's Phrase subscription doesn't include that connector's add-on. This is fixable through your subscription/billing, not through any access-rights toggle. If you can successfully create one connector type but a different type fails with an access-denied error, that's a strong signal you're looking at case 2, not case 1 — a role/rights problem would affect every connector type equally. ## Per-connector-type field quirks The generic connector-creation schema only documents the common base fields (`name`, `type`, `sourceUrl`, `defaultRemoteFolder`, `encodedDefaultRemoteFolder`, `commitMessage`) — it doesn't reliably surface each connector type's own extra fields. A handful of types have field names that don't match what you'd naturally guess: ### Amazon S3 (`AMAZON_S3`) Fields are exactly `apiKey`, `apiSecret`, and `amazonIamRole` — not AWS's own naming (`accessKeyId`/`secretAccessKey`). There is **no `region` field**: the region is embedded directly in the bucket hostname (e.g. `integrations-plugins.qa.eu-west-1.s3.memsource.com`). Sending the wrong field names here doesn't produce a validation error — the API silently accepts `null` credentials and only fails later, at test-connection time, with an unhelpful server error that can look like a platform outage. If test-connection fails right after creating an `AMAZON_S3` connector, check your field names before assuming anything else is wrong. ### Marketo (`MARKETO`) `marketoConnectorType` is required — creation fails without it. Collect it upfront alongside the credentials, not as a follow-up question after the connector already failed to create. You need four things to create a Marketo connector: the API key, the API secret, the API identity URL, and how the customer wants "Create translations" to work. Use the TMS UI's own field labels when asking for credentials — "Marketo API key", "Marketo API secret", and "Marketo API identity URL" — rather than Marketo's native OAuth terminology ("Client ID", "Client Secret", "Munchkin ID"). They map directly to the API's field names, but the host value must be sent as **`identityURL`** in the request body — `host` is a hidden/internal field name and is silently ignored if you send it instead. The identity URL follows the format `https://.mktorest.com/identity` — for example `https://063-RVK-838.mktorest.com/identity`. Find your own instance's value in Marketo Admin → Integration → Web Services. The "Create translations" mode field is `marketoConnectorType`, and its values are not `dynamic`/`static` as you might expect — they match the two options shown in the TMS UI: * `SEPARATED_ASSET` — "as separate documents": translations are created as siblings of the original document, with the locale code appended to the title (e.g. *Black Friday promo \[de-de]*) * `SEGMENTED_DYNAMIC_CONTENT` — "as segmented dynamic content": translations are stored within the original document, with each segment associated with a target locale Required fields are exactly `apiKey`, `apiSecret`, `host` (sent as `identityURL`), and `marketoConnectorType`. Segmentation mapping (`marketoSegmentationMapping`) is optional at the API level even when using segmented dynamic content mode. ### Adobe Experience Manager (`AEM_PLUGIN`) Beyond the base fields: `host` (required), plus optional `basicAuthUserName`/`basicAuthPassword` (used specifically for live preview, not the main connection), `forcedHttps` (boolean), and `urlRewriteFind`/`urlRewriteReplace`. Not OAuth-based. ### WordPress (`WORDPRESS`) WordPress connector credentials are **not** your normal WordPress admin login. They come from the Phrase/Memsource Connector plugin's own settings page on the WordPress site: ``` https:///wp-admin/admin.php?page=memsource-connector ``` On that page, click **"Show Connector settings"** and copy the **"Phrase TMS Connector authentication token"**, plus the username and password shown there. If test-connection returns `GENERAL_ERROR`, check whether the site's host is actually a public URL first. A host like `localhost` or a local development port is unreachable from Phrase's servers entirely, regardless of whether the credentials are correct — you'll need a public URL or a tunnel (e.g. ngrok) for Phrase to reach a local WordPress instance. ### GitHub (plain `GIT` type, credential-based) If you're connecting to a `github.com` (or GitHub Enterprise) host using the plain `GIT` connector type (not `GITHUB`/`GITHUB2`), note that GitHub has rejected real account passwords for Git-over-HTTPS since August 2021. The password field must be a **Personal Access Token**, not your actual account password. An `UNAUTHORIZED` response for a GitHub-hosted `GIT` connector is almost always this. ### Contentstack (`CONTENTSTACK`) `contentStackRegion` is required in practice even though the create-connector schema doesn't mark it required. Omitting it passes request validation, but the backend then fails while converting the missing value, surfacing as a generic `500` rather than a validation error — nothing about that response tells you which field caused it. Send `contentStackRegion` alongside `contentStackAuthType`, `apiKey`, and `sourceLang` (the fields the schema does mark required) on every create request. Valid values are `NORTH_AMERICA`, `EUROPE`, `AZURE_NORTH_AMERICA`, `AZURE_EUROPE`, `GCP_NORTH_AMERICA`, and `CUSTOM` — pick whichever matches where your Contentstack organization is hosted; `NORTH_AMERICA` is the default region for accounts that haven't chosen a specific one. If a `CONTENTSTACK` create request 500s, check for this field before assuming a platform outage. ### Types not listed here For any connector type not covered above, inspect its create-connector request schema directly (use the full schema view in the API reference, not the summarized one) before assuming what fields it needs: a `code`+`redirectUri` field pair means it's OAuth-based (see [OAuth Connector Setup](/en/guides/managing-connectors/oauth-setup)); anything else (a token, an API key, or host+credentials) means it isn't. # Guides Source: https://developers.phrase.com/en/guides/overview Implementation guides for extending Phrase capabilities Learn how to extend Phrase with custom integrations, AI tooling, and bring your own services. Integrate your own machine translation engine into Phrase Language AI using a standardized API interface. Build a plugin for Phrase TMS that sends source content for localization and retrieves translated content. Create, configure, and troubleshoot TMS connectors to Google Drive, GitHub, Amazon S3, WordPress, Marketo, and other third-party systems. Set up a connector to automatically create translation projects on a schedule, and troubleshoot APC's full-replace update behavior. # Phrase MCP Server Source: https://developers.phrase.com/en/mcp-server Connect any Model Context Protocol (MCP)-compatible AI tool to Phrase. The Phrase MCP Server lets an AI assistant work directly with your Phrase data. It can check job status, run quality checks, or start routine work in plain language, without opening Phrase or writing code. Any Phrase account with API access can use it. ## Connect No installation, no tokens to manage. You sign in with your existing Phrase account. **Prerequisites** * An active Phrase account with access to the organization you want to connect * An MCP-compatible AI tool that supports adding a remote server by URL Point your MCP client at the server URL for your region: * EU: `https://mcp.eu.phrase.com` * US: `https://mcp.us.phrase.com` Check your Phrase account URL (`eu.phrase.com` or `us.phrase.com`) if you're not sure which region you're on. Exactly how you register a remote server depends on your client. Refer to its documentation for the precise steps. ```bash theme={null} claude mcp add --transport streamable-http phrase-mcp-prod-eu https://mcp.eu.phrase.com ``` Use `phrase-mcp-prod-us` and the US URL if that's your region. 1. Go to **Settings → Connectors → Advanced settings → Add custom connector**. 2. Name it `Phrase`, paste the server URL for your region, and leave authentication as-is, you'll sign in in the next step. 3. Save the connector. Start the authorization flow from your client. Sign in, pick your organization, and choose what to allow: View data, Create data, or Modify and delete data. Your normal Phrase role permissions still apply. This only restricts what you can do, it never expands it. You can change this later. Run `/mcp` and select the Phrase server. Open the Phrase connector and click **Connect**. Ask your assistant to "fetch my most recent Phrase project." You can view what you've authorized and revoke access anytime from your Phrase profile settings, under the Consents tab. This list is scoped to whichever organization you're signed into. If you connect to more than one organization, check each one separately. To see or manage consents for a different organization, sign out and back in under that organization first. *** ## Troubleshooting The sign-in didn't complete. Restart the authorization flow from your client and try again. Confirm the server shows as connected in your client. The scopes you granted at authorization limit what the assistant can do. Your Phrase role permissions still apply in addition to them, not instead of them. Check what you allowed when you connected. ## What's next Once you're connected, head to **[Starter prompts](/en/mcp-server-starter-prompts)** to see what to try first. *** ## Local install (deprecated) Before the hosted server above, the Phrase MCP Server was a self-hosted, open-source package you ran yourself with your own API tokens. It's still available for teams already using it, but the connect flow above is now the recommended way to get started. Setup, configuration, and troubleshooting for the local install live in the [phrase/phrase-mcp-server](https://github.com/phrase/phrase-mcp-server) README. # Starter prompts Source: https://developers.phrase.com/en/mcp-server-starter-prompts The moment you connect, here's what's worth trying first. These prompts are grouped by what you’re trying to get done. Pick whichever one matches what you’re working on. No code, no need to know the Phrase API. You can't accidentally break anything here. Your AI assistant can only create or change data if you explicitly granted that when you connected. Everything below is safe to try. If in doubt, check what you allowed in your Phrase profile settings, under the Consents tab. Before you start, make sure you've picked the right organization and access level when you connected. See [connecting Phrase to your AI tools](/en/mcp-server) if you need to check. ## Get oriented *First prompt, first win. Confirms the connection works and shows Phrase talking back.* **See what's connected** ```text theme={null} List my 5 most recently updated Phrase projects ``` Pulls a short, recent slice of your projects rather than everything you have access to. Confirms you're connected and pointed at the right organization, without a slow, oversized first response. ## Start building *Now for the good part: things that used to need a ticket to engineering, or just didn't get done. One line, no queue, no waiting.* **Terminology audit** ```text theme={null} How many times did we use 'can't' vs 'cannot' across [project name]? ``` Searches your whole project for both terms and gives you a count. **Placeholder mismatch check** ```text theme={null} Check [job name] for target locales where placeholders don't match the English source, and give me a prioritized list ``` Compares placeholders across every target language against the source and returns a ranked list of mismatches. Catches a broken placeholder, like a missing tag, before it ships. Run it weekly and it's a standing quality gate, no engineering needed. **Automated GitHub pipeline** ```text theme={null} When a new content batch is pushed to [GitHub repo], trigger a Phrase job, assign [MT engine], and notify [Slack channel] once it's done ``` No one has to remember to start this, and no one has to be involved for it to run. **Deadline watch** ```text theme={null} Monitor all active TMS jobs due in the next 48 hours, and message me if any don't have a linguist assigned ``` Checks due dates and linguist assignments across active jobs, and only messages you if something's missing. A standing watch, not a one-time check. **Stale job check** ```text theme={null} List all jobs that haven't been updated in the last year ``` Surfaces jobs with no recent activity, so stale work doesn't sit forgotten until someone asks about it. **Reassign ownership** ```text theme={null} Reassign all of [name]'s live projects to [new owner] ``` Moves ownership across every active project in one step. Useful if someone’s away and the work still needs to move. **Bulk key update** ```text theme={null} Update these 300 keys with the values from this spreadsheet, across [languages] ``` Matches the keys in your spreadsheet to the ones already in the project and updates them in bulk. ## A note on permissions If a prompt above doesn't work, it's usually because it needs access you didn't grant when you connected (see above), not a bug. ## Didn't find what you needed? These prompts are starting points, not a full list. Once you're comfortable, just describe what you're trying to do in your own words. Your AI assistant will work out which Phrase actions it needs. Once you land on a prompt that works well, save it and share it with your team. A small shared library of prompts that actually work is one of the fastest ways to get everyone using this well. ## Found a great use case, or hit a wall? Tell us. This page grows from real examples, several of the prompts above came directly from customers who tried something and it worked. If you've got one worth sharing, or a prompt that should work but doesn't, let us know via the [Phrase Help Center](https://support.phrase.com/hc/requests/new). # Android Source: https://developers.phrase.com/en/ota/android OTA SDK for Kotlin and Java Android apps The Phrase Android SDK fetches OTA translation releases at runtime and caches them on-device. If the OTA service is unreachable, the SDK falls back to the last cached translations or to the strings bundled in your app binary. For more information on requirements and supported platforms, see the repository [README](https://github.com/phrase/phrase-android). ## Installation Add the Phrase Maven repository to your root `build.gradle`, then add the SDK dependency: ```gradle theme={null} // root build.gradle allprojects { repositories { maven { url "https://maven.download.phrase.com" } } } // app/build.gradle dependencies { // With Jetpack Compose support implementation "com.phrase.android:ota-sdk-compose:" // Without Compose (views only) // implementation "com.phrase.android:ota-sdk:" } ``` ## Setup Initialize in your `Application` class and trigger the initial fetch. Both values are available in the Phrase Strings dashboard after creating a distribution, or via the [Distributions API](/en/api/strings/introduction): ```kotlin theme={null} class MainApplication : Application() { override fun onCreate() { super.onCreate() Phrase.setup(this, "YOUR_DISTRIBUTION_ID", "YOUR_ENVIRONMENT_SECRET") Phrase.updateTranslations() } } ``` To react to the result: ```kotlin theme={null} Phrase.updateTranslations(object : TranslationsSyncCallback { override fun onSuccess(translationsChanged: Boolean) { } override fun onFailure() { } }) ``` ## Using translations **Jetpack Compose:** ```kotlin theme={null} Text(phraseString(R.string.your_key)) ``` **Android Views — base activity pattern:** ```kotlin theme={null} open class BaseActivity : AppCompatActivity() { override fun getDelegate() = Phrase.getDelegate(this, wrapContext = false) } ``` Layouts can then reference `@string/your_key` as normal; the SDK intercepts the resource lookup. **Programmatic access:** ```kotlin theme={null} textView.setText(context.getPhraseString(R.string.your_key)) ``` ## Configuration options ```kotlin theme={null} Phrase.setTimeout(20_000) // Network timeout in ms (default: 10,000) Phrase.setDatacenter(Datacenter.US) // Use the US data center (default: EU) Phrase.setAppVersion("2.1.0") // Override detected app version for release targeting ``` `setAppVersion` is useful if your `versionName` does not follow `..` format, which is required for [semantic version targeting](/en/ota/introduction#releases). # Flutter Source: https://developers.phrase.com/en/ota/flutter OTA SDK for Flutter apps The Phrase Flutter SDK delivers OTA translation releases to Flutter apps across all supported platforms: iOS, Android, Linux, macOS, and Windows. The example repository demonstrates a full integration. ## Setup 1. Add the Phrase Flutter SDK to your `pubspec.yaml` 2. Run the Phrase code generator: ```bash theme={null} dart run phrase ``` 3. Create a distribution in Phrase Strings and copy the Distribution ID and environment secret from the dashboard or via the [Distributions API](/en/api/strings/introduction) 4. Initialize the SDK in `main.dart` before rendering any strings: ```dart theme={null} Phrase.setup("YOUR_DISTRIBUTION_ID", "YOUR_ENVIRONMENT_SECRET"); ``` 5. Run your app: ```bash theme={null} flutter run ``` # i18next Source: https://developers.phrase.com/en/ota/i18next OTA backend plugin for i18next `@phrase/i18next-backend` is a backend plugin for [i18next](https://www.i18next.com/) that fetches translations from Phrase OTA at runtime. It works with any JavaScript framework that uses i18next — React, Vue, Angular, Node.js, React Native, and others. The plugin caches translations locally and re-fetches when the cache expires, minimizing requests to the Phrase CDN. This guide applies to v2+ of the SDK. ## Installation ```bash theme={null} npm install --save @phrase/i18next-backend ``` ## Setup ```javascript theme={null} import i18n from "i18next"; import { I18nextPhraseBackend } from "@phrase/i18next-backend"; i18n .use(I18nextPhraseBackend) .init({ fallbackLng: "en", backend: { distribution: "YOUR_DISTRIBUTION_ID", environment: "YOUR_ENVIRONMENT_SECRET", appVersion: "1.0.0", }, }); ``` Both `distribution` and `environment` are available in the Phrase Strings dashboard after creating a distribution, or via the [Distributions API](/en/api/strings/introduction). ## Configuration options | Option | Required | Description | | --------------------- | -------- | ------------------------------------------------------------------------------------------------------- | | `distribution` | Yes | Your OTA distribution ID | | `environment` | Yes | Environment secret — differs between development/beta and production | | `appVersion` | No | (Semantic) app version for release targeting via min/max version constraints | | `cacheExpirationTime` | No | Cache duration in seconds (default: `300`; recommended minimum for production) | | `datacenter` | No | OTA data center — `Datacenter.EU` (default) or `Datacenter.US`, imported from `@phrase/i18next-backend` | | `format` | No | Translation format — defaults to `i18next`; set to `i18next_4` for v4 pluralization | | `storage` | No | Custom async storage implementation for caching. Required on React Native (see below) | ## React Native The backend has no built-in storage on React Native, so pass an `AsyncStorage`-compatible implementation via the `storage` option. Any storage exposing `getItem`, `setItem`, and `clear` (returning Promises) works. ```bash theme={null} npm install --save @phrase/i18next-backend @react-native-async-storage/async-storage ``` ```javascript theme={null} import i18n from "i18next"; import { initReactI18next } from "react-i18next"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { I18nextPhraseBackend } from "@phrase/i18next-backend"; i18n .use(I18nextPhraseBackend) .use(initReactI18next) .init({ fallbackLng: "en", backend: { distribution: "YOUR_DISTRIBUTION_ID", environment: "YOUR_ENVIRONMENT_SECRET", storage: AsyncStorage, }, }); ``` For projects that target both React Native and web via `react-native-web`, passing `AsyncStorage` works on both — its web build is backed by `localStorage`. Alternatively, omit `storage` and the package auto-detects `localStorage` on web. ## Managing releases Create and publish releases using the [Strings API](/en/api/strings/introduction) or the Phrase Strings dashboard. To publish releases automatically on a schedule, use [release triggers](/en/ota/introduction#release-triggers). # Over-the-Air (OTA) Source: https://developers.phrase.com/en/ota/introduction Push translation updates to live apps without a new release Phrase Strings Over-the-Air (OTA) lets you update translations in live applications without submitting a new app version to an app store or redeploying to your server. Once your app integrates our OTA SDK, it fetches translations from the Phrase CDN at runtime. When you publish a new release, users see updated strings as soon as the app has fetched them. OTA currently integrates with iOS, Android, React Native, Flutter, i18next, and Rails. ## Core concepts OTA is built around two resources: **distributions** and **releases**. ### Distributions A distribution defines which Phrase Strings projects, locales, and platforms are bundled for OTA delivery. Each distribution has its own credentials — a **distribution ID** and an **environment secret** — that the SDK uses to authenticate against the Phrase CDN. Multiple distributions are possible, but the recommended setup is one distribution per project. When a distribution targets both iOS and Android, string placeholders between the two formats are automatically converted. A distribution can optionally be restricted to only serve **reviewed translations** — keys that have not passed review are omitted from releases published under that distribution. Distribution settings only take effect on releases published after the change. If you update a distribution (e.g. its fallback languages or reviewed-only setting), publish a new release for connected SDKs to pick it up. #### Language fallbacks A distribution offers three independent fallback options, applied when a requested translation is unavailable or doesn't exist: * **Use language fallback** — serve the fallback languages configured in the project's language settings instead of the requested language. * **Fallback languages exclude regions** (recommended) — if a requested regional language isn't found, the region is dropped and the base language is served instead (e.g. `de-DE` → `de`). * **Fallback languages use the default locale** (recommended) — if the requested language isn't found at all, the project's default locale is served instead (e.g. `en-AU` → `en-US`). Fallbacks do not apply to linked keys. ### Releases A release is a point-in-time snapshot of the translations in a distribution. Publishing a release exports the current project state and makes it available to any device or instance running an SDK configured with that distribution's credentials. Releases support **semantic version constraints**: you can target a release to a range of app versions (e.g. `>= 2.0.0 < 3.0.0`), so users on older versions are not served translations that reference keys added in a newer release. ### Environments Every distribution has two environment secrets: **development** and **production**. The SDK receives releases for whichever environment its secret belongs to. A newly created release is available to the **development** environment immediately. It reaches the **production** environment only once you publish it (using the [API endpoint](/en/api/strings/releases/publish-a-release), or *Publish* in the dashboard). In practice: point debug and QA builds at the development secret to preview a release before it ships, and point store/production builds at the production secret so end users only see releases you have explicitly published. ### Release triggers [Release triggers](https://support.phrase.com/hc/en-us/articles/5804059067804-Over-the-Air-Strings#schedule-ota-releases-0-5) automate release publishing on a cron schedule. Configure a trigger on a distribution to create and publish new releases automatically at a set frequency, without manual intervention. ## Resilience OTA SDKs are designed so that a slow network or an unavailable OTA service never breaks your app. When the SDK cannot reach the Phrase CDN, it resolves translations through a layered fallback chain: 1. **On-device cache** — the last release successfully fetched is stored locally. As long as a device has fetched at least one release, it continues to display those translations indefinitely, regardless of connectivity. 2. **Bundled translations** — if the device has never successfully fetched a release (e.g. on first launch with no network), the SDK falls back to the translation files shipped inside the app binary. Because the bundled translations are the final safety net, keep them up to date with every app release. A device that has never been online will always see the bundled strings, so stale bundles lead to stale copy for those users. ## Usage limits OTA usage is subject to limits based on the number of **requests** and **Monthly Active Users (MAU)**. The exact allowances depend on your Phrase subscription — see the [pricing page](https://phrase.com/pricing/#acc-limits) for your plan's details. ### Data sent with each request Each SDK request to the Phrase CDN includes: the device identifier, app version, cached translation file timestamp, SDK version, requested locale, file format, client type, distribution ID, and environment secret. No other device or user data is transmitted. ## Reports Each distribution provides usage reports, refreshed twice a day, covering: * Active users * Overall requests * Requests per language * Requests per platform * Device languages not covered by the distribution Reports are accessible from the *Over the air* page in the Phrase Strings dashboard. ## Supported SDKs PhraseSDK for Swift and Objective-C apps. Supports SPM, CocoaPods, and Carthage. Kotlin and Java SDK with Jetpack Compose and Android Views support. Cross-platform SDK for iOS, Android, and desktop. SDK for React Native apps on iOS and Android. JavaScript plugin for React, Vue, Angular, Node.js, React Native, and any i18next-based app. Ruby gem that replaces the Rails i18n backend with Phrase OTA. ## Network requirements The SDKs communicate with the following domains. Add them to your allowlist if your network restricts outbound connections: | Data center | Domains | | ------------ | ------------------------------------------------ | | EU (default) | `ota.eu.phrase.com`, `cdn.eu.phrase.com` | | EU (legacy) | `ota.phraseapp.com`, `cdn.phraseapp.com` | | US | `ota.us.phrase.com`, `cdn.us.phrase.com` | | US (legacy) | `ota.us.app.phrase.com`, `cdn.us.app.phrase.com` | ## API reference Manage distributions and releases programmatically. Create and manage OTA distributions. Publish translation snapshots to connected SDKs. Automate release publishing. # iOS Source: https://developers.phrase.com/en/ota/ios OTA SDK for Swift and Objective-C iOS apps The Phrase iOS SDK fetches OTA translation releases at runtime and caches them on-device. If the OTA service is unreachable, the SDK falls back to the last cached translations or to the strings bundled in your app binary. For more information on requirements and supported platforms, see the repository [README](https://github.com/phrase/ios-sdk). ## Installation ```text Swift Package Manager theme={null} Add https://github.com/phrase/ios-sdk/ in Xcode under File → Add Package Dependency ``` ```ruby CocoaPods theme={null} pod 'PhraseSDK' ``` ```text Carthage theme={null} binary "https://raw.githubusercontent.com/phrase/ios-sdk/master/PhraseSDK.json" ~> 5.0.0 ``` For Carthage, run `carthage update --use-xcframeworks` after adding the entry. You can also download the latest release manually and link `PhraseSDK.xcframework` as a binary. ## Setup Call `setup` before any strings are displayed, typically in `AppDelegate.application(_:didFinishLaunchingWithOptions:)` or at the entry point of your SwiftUI app: ```swift theme={null} import PhraseSDK Phrase.shared.setup( distributionID: "YOUR_DISTRIBUTION_ID", environmentSecret: "YOUR_ENVIRONMENT_SECRET" ) ``` Both values are available in [Phrase Strings](https://app.phrase.com/go/ota) after creating a distribution, or via the [Distributions API](/en/api/strings/introduction). ## Fetching and applying translations ```swift theme={null} Task { do { let updated = try await Phrase.shared.updateTranslation() if updated { Phrase.shared.applyPendingUpdates() } } catch { // Falls back to cached or bundled translations automatically } } ``` `applyPendingUpdates()` makes the new strings visible immediately. If omitted, they take effect on the next cold launch. ## Configuration options ```swift theme={null} Phrase.shared.configuration.debugMode = true // Enable verbose SDK logging Phrase.shared.configuration.timeout = 20 // Network timeout in seconds (default: 10) Phrase.shared.configuration.localeOverride = "en-US" // Force a specific locale Phrase.shared.configuration.ignoreOtherTables = true // Only patch the default strings table Phrase.shared.configuration.apiHost = .us // Use the US data center (default: EU) ``` # Ruby on Rails Source: https://developers.phrase.com/en/ota/rails OTA gem for Ruby on Rails applications `phrase-ota-i18n` is a Ruby gem that replaces the default Rails i18n backend with a Phrase-backed one. Instead of reading translations from local YAML files, your application fetches the current release from the Phrase CDN at runtime. Publishing a new release in Phrase Strings propagates to all running instances without a redeploy. If Phrase is unreachable, the gem falls back to the locale files bundled with your application. ## Installation Add to your `Gemfile`: ```ruby theme={null} gem 'phrase-ota-i18n' ``` Then run: ```bash theme={null} bundle install ``` ## Setup Run the Rails generator to create the initializer: ```bash theme={null} bundle exec rails generate phrase_ota:install \ --distribution-id YOUR_DISTRIBUTION_ID \ --secret-token YOUR_SECRET_TOKEN ``` Both parameters are required: | Parameter | Description | | ------------------- | ---------------------------------------------------------------- | | `--distribution-id` | The ID of the distribution you created in Phrase Strings | | `--secret-token` | The environment secret for authenticating against the Phrase CDN | Both values are available in the Phrase Strings dashboard after creating a distribution, or via the [Distributions API](/en/api/strings/introduction). ## Managing releases Create and publish releases using the [Strings API](/en/api/strings/introduction) or the Phrase Strings dashboard. There is no version targeting for Rails releases — all running instances always receive the latest published release. To publish releases automatically on a schedule, use [release triggers](/en/ota/introduction#release-triggers). # React Native Source: https://developers.phrase.com/en/ota/react-native OTA SDK for React Native apps The Phrase React Native SDK delivers OTA translation releases to iOS and Android apps built with React Native. It integrates with [react-i18next](https://react.i18next.com/) as a chained backend, so translations fetched from Phrase are merged with your local resource bundles. It follows the same distribution and release model as the other mobile SDKs — see the [OTA introduction](/en/ota/introduction) for a full explanation of core concepts. Setup instructions, configuration options, and code examples are maintained in the [example app](https://github.com/phrase/react_native_sdk_example). The SDK caches translations and a generated device identifier in `AsyncStorage`. Clearing `AsyncStorage` entirely (for example on logout) causes the app to regenerate that identifier, which inflates your Monthly Active Users count — clear only your own app's keys if you need to reset state.