Apinoa Docs

Translate

Replace the text inside a product image with a translation, keeping the font weight, colours, layout and badge backdrops.

View raw .mdx
POST /v1/image-translate/translate

Send 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.jpg

Parameters

Headers

HeaderRequiredNotes
x-api-keyyesYour API key.
Content-Typeyesimage/jpeg, image/png, image/webp or application/octet-stream.

Query string

ParameterTypeRequiredNotes
source_languagestringyesThe 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_languagestring (2–8)yesThe 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.
fontstringA 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_weightstringauto, 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.
renderbooleantrue (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:

HeaderMeaning
X-Apinoa-Request-IdThe request's id. Quote it if you contact support.
X-Apinoa-Regions-CountHow 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
  }
}
FieldTypeMeaning
inpainted_base64stringThe image with the source text removed, as a base64 JPEG.
regions[].indexintegerThe region's number, starting at 0.
regions[].polygonnumber[][]Four corner points, in the original image's coordinates.
regions[].bboxobjectThe bounding box {x, y, w, h}, in the original image's coordinates.
regions[].textstringThe text that was read.
regions[].text_krstringIts translation, in target_language (the field name is historical).
regions[].confidencenumberRecognition confidence, 0–1.
regions[].text_color, regions[].bg_colorobjectEstimated text and background colours, as RGB.
regions[].bg_stdnumberHow uneven the background is behind the text; near 0 is a flat colour.
regions[].font_weightstringThe detected weight.
regions[].is_badgebooleantrue for text on a filled label, such as a price tag or sale badge.
regions_countintegerHow many regions were found.

Errors

StatusCodeMeaning
400BAD_REQUESTThe body is empty, or a query parameter is invalid.
401UNAUTHORIZEDThe x-api-key header is missing, or the key is invalid.
402INSUFFICIENT_BALANCEThe balance does not cover the call. Retrying does not clear it; top up.
413PAYLOAD_TOO_LARGEThe body is over 20 MB. Downscale before sending.
413IMAGE_TOO_LARGEThe image is over 8192 × 8192 px.
415UNSUPPORTED_MEDIA_TYPEContent-Type is not an image type. Send raw bytes with image/jpeg, image/png or image/webp.
422INVALID_IMAGEThe bytes are not a readable image.
502UPSTREAM_ERRORProcessing is briefly unavailable. Retry; it usually recovers within a minute.
503SERVICE_UNAVAILABLETemporarily 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, decode inpainted_base64 and draw each region's text_kr inside its polygon, using text_color, bg_color and font_weight.
  • Your own font. Upload one and pass font=user/<id>; see Custom Fonts.

On this page