Translate
Replace the text inside a product image with a translation, keeping the font weight, colours, layout and badge backdrops.
POST /v1/image-translate/translateSend the image as raw bytes in the body (not JSON, not base64), and every other parameter in the query
string. You get back the translated JPEG, or with render=false the cleaned image and every text region as
JSON.
Request
curl -X POST "https://gateway.apinoa.com/v1/image-translate/translate?source_language=zh-CN&target_language=ko" \
-H "x-api-key: $APINOA_API_KEY" \
-H "Content-Type: image/jpeg" \
--data-binary @product.jpg \
-o translated.jpgParameters
Headers
| Header | Required | Notes |
|---|---|---|
x-api-key | yes | Your API key. |
Content-Type | yes | image/jpeg, image/png, image/webp or application/octet-stream. |
Query string
| Parameter | Type | Required | Notes |
|---|---|---|---|
source_language | string | yes | The text's language: ch, zh, zh-CN, zh-TW, chinese_cht, ja, japan, en, or auto. auto skips the language check, so every region with a translation is rendered. |
target_language | string (2–8) | yes | The language to translate into, as an ISO 639-style code. Korean, Simplified Chinese, Japanese and Latin-script targets render best; Supported Fonts lists the fonts for each. |
font | string | A value from allFonts in Supported Fonts, or user/<id> for an uploaded custom font. Default Pretendard. Glyphs the font lacks fall back to Pretendard and NotoSansSC. | |
font_weight | string | auto, Thin, Light, Regular, Medium, SemiBold, Bold, ExtraBold or Black. Default ExtraBold. auto matches each region's original weight; any other value applies to every region. | |
render | boolean | true (default) returns the finished image; false returns the cleaned image and the regions as JSON, to draw yourself. |
Response
render=true (Default): The Image
The body is the translated JPEG (Content-Type: image/jpeg), with these headers:
| Header | Meaning |
|---|---|
X-Apinoa-Request-Id | The request's id. Quote it if you contact support. |
X-Apinoa-Regions-Count | How many text regions were detected and replaced. |
An image with no text comes back unchanged, with X-Apinoa-Regions-Count: 0.
render=false: The Regions as JSON
A real response, shortened to its first region:
{
"success": true,
"requestId": "240d4c0348574bd7bc12f8e5d8780a87",
"data": {
"inpainted_base64": "/9j/4AAQSkZJRgABAQAA…",
"regions": [
{
"index": 0,
"polygon": [[83, 68], [352, 68], [352, 145], [83, 145]],
"bbox": { "x": 83, "y": 68, "w": 269, "h": 77 },
"text": "限时特价",
"text_kr": "기간 한정 특가",
"confidence": 0.999354,
"text_color": { "r": 255, "g": 253, "b": 252 },
"bg_color": { "r": 211, "g": 40, "b": 43 },
"bg_std": 0.418889,
"font_weight": "Regular",
"is_badge": false
}
],
"regions_count": 3
}
}| Field | Type | Meaning |
|---|---|---|
inpainted_base64 | string | The image with the source text removed, as a base64 JPEG. |
regions[].index | integer | The region's number, starting at 0. |
regions[].polygon | number[][] | Four corner points, in the original image's coordinates. |
regions[].bbox | object | The bounding box {x, y, w, h}, in the original image's coordinates. |
regions[].text | string | The text that was read. |
regions[].text_kr | string | Its translation, in target_language (the field name is historical). |
regions[].confidence | number | Recognition confidence, 0–1. |
regions[].text_color, regions[].bg_color | object | Estimated text and background colours, as RGB. |
regions[].bg_std | number | How uneven the background is behind the text; near 0 is a flat colour. |
regions[].font_weight | string | The detected weight. |
regions[].is_badge | boolean | true for text on a filled label, such as a price tag or sale badge. |
regions_count | integer | How many regions were found. |
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | BAD_REQUEST | The body is empty, or a query parameter is invalid. |
| 401 | UNAUTHORIZED | The x-api-key header is missing, or the key is invalid. |
| 402 | INSUFFICIENT_BALANCE | The balance does not cover the call. Retrying does not clear it; top up. |
| 413 | PAYLOAD_TOO_LARGE | The body is over 20 MB. Downscale before sending. |
| 413 | IMAGE_TOO_LARGE | The image is over 8192 × 8192 px. |
| 415 | UNSUPPORTED_MEDIA_TYPE | Content-Type is not an image type. Send raw bytes with image/jpeg, image/png or image/webp. |
| 422 | INVALID_IMAGE | The bytes are not a readable image. |
| 502 | UPSTREAM_ERROR | Processing is briefly unavailable. Retry; it usually recovers within a minute. |
| 503 | SERVICE_UNAVAILABLE | Temporarily over capacity. Retry with backoff. |
Every code is listed in Errors. Failed calls are not billed.
Pricing
Each call is charged at the image-translate rate on the pricing page.
Notes
- Limits. Images up to 8192 × 8192 px and a 20 MB body, as JPEG, PNG or WebP.
- Timeouts. Most calls finish in 1.5–3 seconds; under heavy load one can take up to 5 minutes. Set your HTTP client's timeout to at least 300 seconds so a slow answer is not cut off on your side.
- Drawing it yourself. With
render=false, decodeinpainted_base64and draw each region'stext_krinside itspolygon, usingtext_color,bg_colorandfont_weight. - Your own font. Upload one and pass
font=user/<id>; see Custom Fonts.