Machine Translation
Comvi returns translation suggestions from several providers: one key at a time, as a stream, or as a batch job over many keys.
Machine translation spends the organization’s credits, so it stays with a signed-in person. Every endpoint needs machine_translation.use; the configured-providers read needs machine_translation.view. No scope grants either, so a key built from the six scopes gets 403 FORBIDDEN on every call; only a key created over the API with the raw permission string machine_translation.use passes. Language restrictions apply to the source and the target locale separately.
Common errors: 401 AUTHENTICATION_REQUIRED, 403 FORBIDDEN (missing permission for the source or target locale, or an API key), 403 READ_ONLY_MODE on writes. See Errors.
Providers
Section titled “Providers”| Provider | ID | Type | Glossary terms in the prompt |
|---|---|---|---|
| Google Translate | google |
Traditional | No |
| DeepL | deepl |
Traditional | No |
| Amazon Translate | aws |
Traditional | No |
| Azure Translator | azure |
Traditional | No |
| OpenAI | openai |
AI | Yes |
| Anthropic Claude | anthropic |
AI | Yes |
Glossary terms, no-translate terms, translation memory matches, the key description and the project’s AI instructions are assembled into a prompt for the AI providers only. Traditional providers receive the source text and nothing else. Availability depends on the keys the instance administrator has configured.
ICU plural and select messages, including a select wrapping a plural, go through the same suggestions endpoint as plain messages: send the whole message as sourceText. An AI provider translates the whole pattern and rebuilds it with the target language’s plural categories, so an English one/other message can come back with the Ukrainian one/few/many/other set. A traditional provider translates each form on its own and keeps the source’s categories.
GET /v1/projects/{projectId}/mt/configured-providers
Section titled “GET /v1/projects/{projectId}/mt/configured-providers”Which providers are available on the server. machine_translation.view.
| Parameter | In | Type | Required | Meaning |
|---|---|---|---|---|
projectId |
path | integer |
Yes | Project ID |
curl -b cookies.txt https://api.comvi.io/v1/projects/1/mt/configured-providers{ "providers": { "google": true, "deepl": true, "aws": false, "azure": false, "openai": true, "anthropic": true } }POST /v1/projects/{projectId}/mt/suggestions
Section titled “POST /v1/projects/{projectId}/mt/suggestions”Ask each configured provider for a suggestion for one key. Rate limit: 60 requests per minute per caller per project. Suggestions are cached; editing a glossary, the translation memory or the AI instructions does not invalidate the cache, so clear it with DELETE /v1/projects/{projectId}/mt/suggestions.
| Parameter | In | Type | Required | Meaning |
|---|---|---|---|---|
projectId |
path | integer |
Yes | Project ID |
key |
body | string |
Yes | Key name, 1 to 512 characters |
namespace |
body | string |
No | Default default |
sourceLocale |
body | string |
Yes | Source language code |
targetLocale |
body | string |
Yes | Target language code. Must differ from sourceLocale |
sourceText |
body | string |
No | Text to translate; resolved from the key if omitted |
limit |
body | integer |
No | Providers to ask, 1 to 10, default 5. With six providers configured, pass 10 to ask them all |
curl -X POST -b cookies.txt -H "Content-Type: application/json" \ -d '{"key": "welcome.message", "sourceLocale": "en", "targetLocale": "uk", "limit": 3}' \ https://api.comvi.io/v1/projects/1/mt/suggestions[ { "providerId": "google", "providerLabel": "Google Translate", "text": "Ласкаво просимо до нашого додатку!" }, { "providerId": "openai", "providerLabel": "OpenAI", "text": "Вітаємо у нашому застосунку!" }]| Status and code | When |
|---|---|
400 INVALID_INPUT |
sourceLocale and targetLocale are the same |
403 LIMIT_EXCEEDED |
The organization has used all its MT credits |
422 FIELD_REQUIRED |
key, sourceLocale or targetLocale is missing |
422 VALIDATION_ERROR |
limit is outside 1 to 10, or a field has the wrong type |
429 TOO_MANY_REQUESTS |
More than 60 requests in a minute |
DELETE /v1/projects/{projectId}/mt/suggestions
Section titled “DELETE /v1/projects/{projectId}/mt/suggestions”Delete the cached suggestions for one key and locale pair, for every provider. Idempotent: an unknown key or an empty cache returns { "deleted": 0 }, not 404. Rate limit: 30 requests per minute per caller per project.
| Parameter | In | Type | Required | Meaning |
|---|---|---|---|---|
projectId |
path | integer |
Yes | Project ID |
key |
body | string |
Yes | Key name, 1 to 512 characters |
namespace |
body | string |
No | Default default |
sourceLocale |
body | string |
Yes | Source language code |
targetLocale |
body | string |
Yes | Target language code |
curl -X DELETE -b cookies.txt -H "Content-Type: application/json" \ -d '{"key": "welcome.message", "sourceLocale": "en", "targetLocale": "uk"}' \ https://api.comvi.io/v1/projects/1/mt/suggestions{ "deleted": 3 }| Status and code | When |
|---|---|
400 INVALID_INPUT |
sourceLocale and targetLocale are the same |
422 FIELD_REQUIRED |
key, sourceLocale or targetLocale is missing |
422 FIELD_TOO_LONG |
key over 512 characters, or a locale code over 50 |
422 FIELD_TOO_SHORT |
key or a locale code is empty |
429 TOO_MANY_REQUESTS |
More than 30 requests in a minute |
GET /v1/projects/{projectId}/mt/suggestions/stream
Section titled “GET /v1/projects/{projectId}/mt/suggestions/stream”The same suggestions as Server-Sent Events, for EventSource. This variant waits for every provider and then writes all suggestion events at once, followed by done. Every 15 seconds the server writes an SSE comment, : ping <milliseconds>, which EventSource ignores. A failure mid-stream arrives as an error event carrying { "message": "..." } and the stream closes; it is not an HTTP status, because the headers were already sent.
| Parameter | In | Type | Required | Meaning |
|---|---|---|---|---|
projectId |
path | integer |
Yes | Project ID |
key |
query | string |
Yes | Key name |
sourceLocale |
query | string |
Yes | Source language code |
targetLocale |
query | string |
Yes | Target language code |
namespace |
query | string |
No | Namespace |
sourceText |
query | string |
No | Text to translate |
limit |
query | integer |
No | 1 to 10, default 5 |
const url = new URL('https://api.comvi.io/v1/projects/1/mt/suggestions/stream');url.searchParams.set('key', 'welcome.message');url.searchParams.set('sourceLocale', 'en');url.searchParams.set('targetLocale', 'uk');const source = new EventSource(url, { withCredentials: true });source.addEventListener('suggestion', (e) => console.log(JSON.parse(e.data).text));source.addEventListener('error', (e) => { if (e.data) console.error(JSON.parse(e.data).message); source.close(); });source.addEventListener('done', () => source.close());POST /v1/projects/{projectId}/mt/suggestions/stream
Section titled “POST /v1/projects/{projectId}/mt/suggestions/stream”The same suggestions as newline-delimited JSON, delivered as they land. The body is the same as POST /v1/projects/{projectId}/mt/suggestions. Every 15 seconds the server writes a bare newline as a keep-alive, so skip blank lines before parsing.
{"event":"suggestion","data":{"providerId":"google","providerLabel":"Google Translate","text":"Ласкаво просимо!"}}{"event":"suggestion","data":{"providerId":"deepl","providerLabel":"DeepL","text":"Ласкаво просимо!"}}{"event":"done","data":{}}POST /v1/projects/{projectId}/keys/batch/mt
Section titled “POST /v1/projects/{projectId}/keys/batch/mt”Translate many keys into one or more target locales. One job is queued per target locale, each attempted up to 3 times with exponential backoff starting at 10 seconds.
| Parameter | In | Type | Required | Meaning |
|---|---|---|---|---|
projectId |
path | integer |
Yes | Project ID |
keyIds |
body | integer[] |
Yes | At least one |
sourceLocaleCode |
body | string |
Yes | Source language code |
targetLocaleCodes |
body | string[] |
Yes | At least one. No duplicates, none equal to the source |
overwriteExisting |
body | boolean |
No | Default false |
curl -X POST -b cookies.txt -H "Content-Type: application/json" \ -d '{"keyIds": [42, 43, 44, 45], "sourceLocaleCode": "en", "targetLocaleCodes": ["uk", "de"]}' \ https://api.comvi.io/v1/projects/1/keys/batch/mtReturns 202 Accepted. There is no top-level jobId; poll each entry of jobs[]. totalKeys counts the keys sent, not keys times locales.
{ "jobs": [{ "jobId": "1042", "targetLocaleCode": "uk" }, { "jobId": "1043", "targetLocaleCode": "de" }], "status": "queued", "totalKeys": 4, "message": "2 batch MT job(s) queued. Subscribe to SSE events for project 1 to receive progress updates."}| Status and code | When |
|---|---|
400 INVALID_INPUT |
targetLocaleCodes has duplicates, or one equals sourceLocaleCode |
403 LIMIT_EXCEEDED |
The organization has used all its MT credits |
422 FIELD_REQUIRED |
keyIds, sourceLocaleCode or targetLocaleCodes is missing |
422 VALIDATION_ERROR |
keyIds or targetLocaleCodes is empty |
GET /v1/projects/{projectId}/keys/batch/mt/{jobId}/status
Section titled “GET /v1/projects/{projectId}/keys/batch/mt/{jobId}/status”Poll one batch job. result is present only when status is completed; a failed job carries error instead.
| Parameter | In | Type | Required | Meaning |
|---|---|---|---|---|
projectId |
path | integer |
Yes | Project ID |
jobId |
path | string |
Yes | A jobId from jobs[] |
curl -b cookies.txt https://api.comvi.io/v1/projects/1/keys/batch/mt/1042/status{ "jobId": "1042", "status": "completed", "progress": 100, "result": { "processed": 4, "failed": 0, "duration": 3200.5, "errors": [] } }status |
Meaning |
|---|---|
waiting |
In the queue |
active |
Being processed |
completed |
Finished |
failed |
Failed |
| Status and body | When |
|---|---|
404 { "error": "Job not found" } |
Unknown job, or one from another project. Not the standard envelope |
POST /v1/projects/{projectId}/keys/batch/mt/{jobId}/cancel
Section titled “POST /v1/projects/{projectId}/keys/batch/mt/{jobId}/cancel”Cancel a queued job. A job that has started cannot be stopped: the response is 200 with success: false and a message saying it is active, completed or failed. Check success, not the status code.
curl -X POST -b cookies.txt https://api.comvi.io/v1/projects/1/keys/batch/mt/1042/cancel{ "success": true, "message": "Job cancelled successfully" }| Status and body | When |
|---|---|
404 { "error": "Job not found" } |
Unknown job |
Next steps
Section titled “Next steps”- Translations to apply suggestions and follow
batch_mt.*events - Projects to configure providers per project
- Glossaries for terminology in the prompt