---
title: "Custom fonts"
description: "Upload your own TTF / OTF / WOFF2 font and reference it in /v1/image-translate/translate as font=\"user/<id>\"."
---

## Overview

Upload your own TTF, OTF or WOFF2 font in the dashboard, then pass `font=user/<id>` in any
`/v1/image-translate/translate` request to render the translated text in your font instead of the
bundled defaults.

Use cases:
- Match your storefront's brand typography on translated product pages
- Render Korean webtoons in a font your readers expect
- Use a Hangul/Han hybrid that's not in the bundled set

## Upload

Sign in, open **Custom fonts** in the sidebar, drop a TTF / OTF / WOFF2 file, give it a display name,
and upload. The dashboard shows each font's `user/<id>` reference and which scripts it can render.

## Rendering with a user font

Pass `font=user/<id>` as a query parameter on `/v1/image-translate/translate`. The body is still the raw image bytes:

```bash
curl -X POST "https://gateway.apinoa.com/v1/image-translate/translate?source_language=zh-CN&target_language=ko&font=user/fxa9b21c0c8f&font_weight=Bold" \
  -H "x-api-key: $APINOA_API_KEY" \
  -H "Content-Type: image/jpeg" \
  --data-binary @product.jpg \
  -o translated.jpg
```

## Glyph coverage gate

If you request `target_language=ko` with a Latin-only font, the request is rejected before any rendering work happens:

```json
{
  "success": false,
  "error": {
    "code": "FONT_GLYPH_COVERAGE",
    "message": "font does not contain glyphs for hangul (required for target_lang=ko). Upload a font that supports this script."
  }
}
```

The gate maps `target_language` to a required script:

| target_language | Required script |
|-----------------|-----------------|
| ko | hangul |
| ja | kana |
| zh, zh-CN, zh-TW | han |
| ru | cyrillic |
| en, fr, de, es, pt, it, vi, id, ms | latin |
| he | hebrew |
| ar | arabic |

If your target language isn't listed, no gate runs.

## Listing your fonts

`/v1/image-translate/supported-fonts` returns your uploaded fonts alongside the bundled ones. Each
carries a `glyphCoverage` map of the scripts it can render — use it to decide which fonts to offer for
each target language:

```bash
curl https://gateway.apinoa.com/v1/image-translate/supported-fonts \
  -H "x-api-key: $APINOA_API_KEY"
```

```json
{
  "fontsByLanguage": { ... },
  "defaultByLanguage": { ... },
  "allFonts": [...],
  "userFonts": [
    {
      "id": "fxa9b21c0c8f",
      "ref": "user/fxa9b21c0c8f",
      "displayName": "Pretendard Bold (storefront)",
      "family": "Pretendard",
      "weight": 700,
      "italic": false,
      "format": "ttf",
      "glyphCoverage": { "latin": true, "hangul": true }
    }
  ]
}
```

## Limits

- Max file size: **10 MiB** per upload
- Accepted formats: TTF, OTF, WOFF2 (TTC/OTC collections are rejected — upload individual styles separately)
- Soft cap of 50 fonts per user — contact sales if you need more

## Deleting a font

Delete a font under **Dashboard > Custom fonts**. Requests that still reference it fail with
`FONT_NOT_READY` until you switch them to another font.

## Errors

These are returned by `/v1/image-translate/translate` when it is given a `user/<id>` font. Problems
with the file itself — size, format, a font with no usable glyphs — are reported in the dashboard when
you upload it.

| Code | When it fires |
|------|---------------|
| `FONT_NOT_FOUND` | `user/<id>` doesn't exist or isn't one of your fonts |
| `FONT_NOT_READY` | The font was deleted or rejected |
| `FONT_GLYPH_COVERAGE` | The font lacks glyphs for the target language's script |
