Skip to main content
Machine translation powered by Phrase picks the best available engine for a given piece of content using AI. BYO (Bring Your Own) Engine lets you plug a custom machine translation engine into that selection by implementing a small, standardized HTTP API. Once your adapter implements the endpoints below, Phrase Language AI can route translation jobs to it like any other engine. This guide covers the whole flow: what your adapter needs to expose, how authentication works, every endpoint you need to implement, and how to harden it for production traffic.

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.
Both translation modes support ad-hoc glossaries and custom request-level metadata. Per-segment metadata is also accepted, but is currently reserved for future use — see Glossaries and custom metadata.

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-Token header.

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:

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.
Response

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 doesn’t allow larger batches, it just decouples submission from result retrieval so slower translations don’t hold a request open.
Implement these endpoints with thread safety and proper concurrency handling — concurrent requests for different jobs must not overwrite each other’s data.

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 glossary array of { term, translation } pairs (0–500 entries, each field 1–50 characters) on either /translate or /translateAsync to enforce specific terminology during translation.
  • Custom metadata — pass a metadata object at the request level on either endpoint. Combine it with dynamic metadata placeholders to pass job context to your engine without extra integration work. A metadata object can also be set per segment, but this field is currently a reserved placeholder for future use — don’t rely on your engine receiving it yet.

Rate limiting and errors

If your engine needs to shed load, respond with 429 and a Retry-After header (seconds until the client may retry):
For any other failure, return an error object:

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