translate
Translate text across 42 languages with source detection and RTL metadata.
Endpoint and method
POST https://metaphrase.msalman.com/api/v1/translate
Authentication
Send Authorization: Bearer <key> and Content-Type: application/json. Create a key at the dashboard. Store it in backend environment variable METAPHRASE_API_KEY; never expose it in a browser, mobile binary, public repository, or widget. See authentication and a working backend proxy.
Request parameters
JSON uses snake_case. Unknown fields are rejected. Omit optional values instead of sending null. Maximum text length: 20,000 Unicode code points.
| Name | Type | Required | Default | Allowed values / range | Max length / items |
|---|---|---|---|---|---|
text | string | Yes | — | — | 20000 |
source_language | string | No | "auto" | auto, en, ur, hi, ar, es, fr, de, pt, it, nl, pl, uk, ru, tr, fa, he, bn, pa, ta, te, mr, gu, ne, si, zh, zh-TW, ja, ko, id, ms, vi, th, tl, sv, da, no, fi, el, cs, ro, hu, sw | — |
target_language | string | Yes | — | en, ur, hi, ar, es, fr, de, pt, it, nl, pl, uk, ru, tr, fa, he, bn, pa, ta, te, mr, gu, ne, si, zh, zh-TW, ja, ko, id, ms, vi, th, tl, sv, da, no, fi, el, cs, ro, hu, sw | — |
stream | boolean | No | false | — | — |
text: Plain text. Limit counts Unicode code points.source_language: Source language code or auto. Detection is heuristic and may be uncertain.target_language: Required translation target language code. ur/ar/fa/he return direction=rtl.stream: Use true for SSE on paraphrase/rewrite, translate or summarize. Other operations require false; alternatives always returns JSON.
source_language is a local heuristic estimate for auto, or und if unknown. The writing provider also detects the source directly. For Urdu, Arabic, Persian and Hebrew use dir="rtl"; the response supplies direction. An explicitly identical source/target returns the input with zero model tokens.
Full example request
{
"text": "A good idea can come from anywhere.",
"source_language": "auto",
"target_language": "ur",
"stream": false
}
Full example response
HTTP 200, application/json. This is an illustrative response; writing, source metadata, token counts and cost can vary. request_id is a server-generated UUID. Cache hits use usage.cached=true and report zero new tokens/cost. usage_estimated=true means the provider did not supply exact token counts.
{
"request_id": "019b8df0-1234-4000-8000-000000000004",
"tool": "translate",
"result": {
"text": "ایک اچھا خیال کہیں سے بھی آ سکتا ہے۔",
"source_language": "en",
"target_language": "ur",
"source_language_detected": true,
"direction": "rtl"
},
"usage": {
"input_tokens": 60,
"output_tokens": 20,
"total_tokens": 80,
"estimated_cost_usd": 0.000016,
"usage_estimated": false,
"cached": false,
"provider": "primary",
"model": "gpt-6-luna"
},
"input_words": 7,
"output_words": 9
}
Errors: cause and fix
Every error uses this JSON shape and a link to its exact fix:
{
"error": {
"code": "unauthorized",
"message": "A valid API key is required.",
"docs_url": "https://metaphrase.msalman.com/docs/errors#unauthorized"
}
}
| Code | HTTP | Cause | Fix |
|---|---|---|---|
invalid_request | 400 | Check the request fields and their allowed values. | Send the documented JSON fields with the correct types. Unknown fields are rejected. |
invalid_json | 400 | The request body is not valid JSON. | Serialize the request with JSON.stringify or your language's JSON encoder. |
unsupported_media_type | 415 | Send application/json content. | Set Content-Type: application/json. File uploads use their separate documented route. |
body_too_large | 413 | The request body exceeds the allowed size. | Reduce the payload and split long documents at sentence boundaries. |
text_too_long | 413 | The text exceeds the configured character limit. | Use the max_input_chars value in the API specification and split longer documents. |
unauthorized | 401 | A valid API key is required. | Send Authorization: Bearer YOUR_KEY. Create a new key if the old one was revoked. |
forbidden | 403 | This action is not available to this account. | Check account status and the key's access permissions. |
rate_limited | 429 | Too many requests. Please wait and try again. | Wait for Retry-After seconds and use exponential backoff with jitter. |
quota_exceeded | 429 | The monthly usage quota has been reached. | Wait for the next UTC calendar month or ask an administrator to change the plan. |
service_unavailable | 503 | A required service is temporarily unavailable. | Wait and retry. The operator should check Redis, PostgreSQL, or the tool's health. |
not_found | 404 | This resource does not exist. | Check the API version, endpoint name, and resource identifier. |
method_not_allowed | 405 | This HTTP method is not supported. | Use POST for processing endpoints and the method documented for dashboard routes. |
internal_error | 500 | The request could not be completed. | Retry once. If it persists, provide the X-Request-Id header to the operator. |
budget_exceeded | 429 | The writing service has reached its configured spending limit. | The operator must review usage and adjust the configured budget before more paid requests can run. |
provider_not_configured | 503 | The writing provider is not configured yet. | The operator must configure LLM_PRIMARY_API_KEY or a fallback provider in .env and recreate the web container. |
upstream_unavailable | 503 | The writing provider is temporarily unavailable. | Retry with backoff. The operator can inspect provider availability without logging submitted text. |
upstream_timeout | 504 | The writing provider took too long to respond. | Retry a shorter input or wait before retrying. Do not append a retry to partial streamed output. |
upstream_error | 502 | The writing provider returned an invalid response. | Retry once with a shorter input. If it continues, the operator should check the configured model's compatibility. |
output_truncated | 502 | The response reached its output limit before finishing. | Use a shorter input or ask the operator to adjust the tool's output cap and chunk size. |
For streaming requests, failures after HTTP headers are sent arrive as an SSE error event with this same error object. Never treat partial text as a completed result or append output from a retry.
Rate limits and quotas
Defaults: Free 15 requests per 60 seconds and 500 accepted calls per key per UTC calendar month; Pro placeholders 120/60 seconds and 25,000/month. The operator can change plans; response headers are authoritative. Calls to all tools share a key's limits. Accepted cache hits and upstream failures consume quota. Authentication/schema failures and provider-not-configured preflight failures do not. X-RateLimit-Remaining, X-RateLimit-Reset, X-Quota-Remaining and X-Quota-Reset show remaining capacity and Unix-second reset times. For HTTP 429 wait Retry-After seconds; quota/budget limits need a reset or operator action. Requests may also receive 429 when the shared processing slots are busy. See retries and long texts.