What you’ll build
A minimal BYO Engine adapter exposes:- Engine status — lets Phrase check your engine is healthy before routing jobs to it.
- Supported languages — tells Phrase which source/target language pairs your engine can translate.
- Synchronous translation — translates a batch of segments and returns the result in the same request.
- Asynchronous translation — accepts a batch of segments, returns immediately with a job ID, and lets Phrase poll for status and results.
What to expect from Phrase
Design your adapter for the traffic Phrase actually sends.Segment counts
- Synchronous calls (
POST /translate) from the Phrase editor normally carry 1 segment. Synchronous calls from other sources can carry more than one segment, and the engine validation test sends 500 segments in one synchronous call. - Asynchronous calls (
POST /translateAsync), used for example by pre-translation and analysis, can carry up to 500 segments. - Both endpoints accept 1 to 500 segments per request. If Phrase has more segments to translate, it splits them into several requests of at most 500 segments before calling your adapter. Your adapter never has to handle more than 500 segments in one request.
Engine validation test
When you validate your engine in Phrase, it runs these checks in order: supported languages, engine status, a synchronous request with 500 segments, a synchronous request with 1 segment, and an asynchronous request with 500 segments. For the translation checks, the number of translated segments in the response must match the number sent.Retries and timeouts
-
Phrase retries a request when your adapter responds with
429,502,503, or504. The wait between attempts grows with each retry, and aRetry-Afterheader is honored when it asks for a longer wait. Retries stop when the time limit for that call runs out, and the call then fails. - Any other error status fails the call. Phrase does not fall back from synchronous to asynchronous translation.
-
Time limits per call:
Prerequisites
- An HTTPS endpoint you control that can implement the OpenAPI schema below.
- Either an OAuth 2.0 client credentials setup or an API token to authenticate incoming requests from Phrase.
- For a working starting point, see the reference adapter implementation, which demonstrates a basic integration and includes additional guidance.
Authentication
Phrase authenticates to your engine using either of the following — support at least one:-
OAuth 2.0 client credentials flow. Phrase requests a token from your token endpoint and sends it as
Authorization: Bearer <token>. Scopes are granted per operation: -
API token. Phrase sends a static token in the
X-Api-Tokenheader.
Token request for client credentials
When you choose Client credentials (OAuth 2.0), you configure a token URL, a client ID and a client secret, and optionally a scope. Phrase sends this request to the token URL:- The client ID and client secret are sent in the
Authorizationheader using HTTP Basic authentication, not in the request body. Each value is URL-encoded before it is Base64-encoded, as described in RFC 6749, section 2.3.1. - The
scopeparameter is sent only when you fill in the optional Scope field. If the field is empty, the request body contains onlygrant_type=client_credentialsand noscope. For several scopes, separate them with spaces, as defined by OAuth 2.0. Phrase doesn’t add the per-operation scopes listed above on its own. If your token endpoint issues scopes based on the request, enter the ones your adapter needs in the Scope field. - Phrase reuses the returned access token until shortly before it expires, and for at most one hour. It requests a new token after that, or when the credentials or the scope change.
/.default, such as api://my-adapter/.default. Enter that value in the Scope field.
Before the Scope field was available, Phrase never sent a
scope parameter. If your identity provider needs a scope and you set up your engine before this field existed, you may have used a proxy token endpoint that added the scope on your side. You can now remove that workaround and set the scope directly.Dynamic metadata
Phrase automatically resolves the following placeholders in request-level metadata values before sending them to your engine:
Use these to pass contextual information about the translation job to your engine without any additional integration work, for example:
Request correlation header
Every request Phrase sends to your engine, including status and supported languages calls, carries anX-Phrase-Action-Id header. It identifies the Phrase action that triggered the request, so you can correlate your logs with Phrase when you ask support to investigate an issue. We recommend logging it with each request you handle. Don’t rely on its format.
Segment metadata
Each segment in a request can carry ametadata object with context about that segment. Phrase currently sends it only when the translation is requested from the Phrase editor. Requests from other sources, such as pre-translation and analysis, don’t include it, so your adapter must work without it. You may ignore it entirely. It is request-side only: you don’t need to return or echo it in the response, and Phrase ignores any metadata on response segments.
Engine status
POST /status — lets Phrase check that your engine is operational before routing work to it.
Request body (optional)
Response
Supported languages
POST /languages — tells Phrase which source/target language pairs your engine can translate.
Request body (optional)
Response
Synchronous translation
POST /translate — translates a batch of segments and returns the result in the same request. Use this for latency-sensitive requests, where the caller can wait for the result inline.
Request body
When a segment includes
idx, echo it back unchanged on the corresponding segment in the response — it’s Phrase’s internal identifier for matching translated segments back to their source, and must not be altered by your adapter.Asynchronous translation
Use the asynchronous flow whenever translation may take longer than a single request should reasonably wait for. Both flows accept the same request shape and the same 1–500 segment limit. Async does not allow larger batches; it decouples submission from result retrieval so slower translations don’t hold a request open.1. Submit the job
POST /translateAsync — accepts the same request body as synchronous translation (source/target language, segments, optional glossary and metadata) and returns immediately with a job ID.
2. Poll for status
GET /translateAsyncStatus/{id} — poll using the job ID until the job is no longer running.
3. Fetch the result
GET /translateAsyncResult/{id} — once status is done, fetch the translated segments. The response has the same shape as the synchronous translation response.
Glossaries and custom metadata
- Glossaries — pass a
glossaryarray of{ term, translation }pairs (0–500 entries, each field 1–50 characters) on either/translateor/translateAsyncto enforce specific terminology during translation. - Custom metadata — pass a
metadataobject at the request level on either endpoint. Combine it with dynamic metadata placeholders to pass job context to your engine without extra integration work. Phrase also sends ametadataobject per segment in some cases, see Segment metadata.
Rate limiting and errors
If your engine needs to shed load, respond with429 and a Retry-After header (seconds until the client may retry):
Stability and performance recommendations
Load coming from Phrase can be bursty, especially with concurrent asynchronous jobs. Before going to production:- 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 proxy/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.
Reference
- Demo implementation — a reference adapter demonstrating a basic integration.
- OpenAPI schema — implement your adapter in accordance with this schema.
Full API Schema
Explore the raw schema to see all endpoints in one place. Perfect for tools and integration setup.