Documentation

Make your first call in 5 minutes

Get a key, send a request, read the response — in that order.

1. Get an API key

Generate a free test key on the Get API Key page. New accounts receive testing quota automatically.获取 API Key页面生成免费测试 Key。新账户将自动获得测试额度。

2. Send a request

curl -X POST https://api.chinesekey.org/v1/decompose \
  -H "Authorization: Bearer pk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "text": "清",
    "density": "full",
    "lang": "en",
    "variant": "simp"
  }'

3. Read the response

{
  "code": 0,
  "data": {
    "text": "清",
    "variant": "simp",
    "pinyin": "qīng",
    "audio": null,
    "views": {
      "character": {
        "char_type": "PHONO",
        "structure": { "components": ["氵", "青"] },
        "semantic": { "component": "氵", "root": "水",
          "meaning": "与「水」相关", "meaning_en": "related to water",
          "meaning_ja": "水に関連" /* …+ ko/vi/th/id/ru/es/fr/de/pt/ar */ },
        "phonetic": { "component": "青", "root": "青", "weak": false },
        "explanation": "清 is a Semantic-phonetic character…",
        "families": [
          { "role": "意符", "center": "水", "members": [{"c":"济","py":"jì"}, ] },
          { "role": "声符", "center": "青", "members": [{"c":"情","py":"qíng"}, ] }
        ]
      },
      "word": {
        "pos": "Adjective Verb",
        "meaning": "pure; clean; clear; distinct; fresh…",
        "examples": ["…"]
      }
    }
  },
  "meta": { "source": "HanziPeek", "version": "2.0", "request_id": "f3dd8be4-...", "lang_coverage": "full" }
}

A single character returns both views.character (structure) and views.word (vocabulary) — they're two different lenses on the same input, not a hierarchy. A multi-character word returns views.word only, with a parts[] breakdown of each character's own dictionary sense.单字会同时返回 views.character(结构)和 views.word(词汇)——这是同一个输入的两个平行视角,不是谁包含谁。多字词只返回 views.word,附带 parts[] 逐字词义。

API Reference

Authentication & endpoint

Value
ProtocolHTTPS
Base URLhttps://api.chinesekey.org
EndpointPOST /v1/decompose
Auth headerAuthorization: Bearer <your_api_key>
Content typeapplication/json
Rate limitSet per plan — see Pricing. Current usage isn't returned per-request; check your dashboard.
Statusstatus.chinesekey.org — live uptime, checked every 5 minutes

Request parameters

ParamTypeRequiredDescription
textstringYes1–4 Chinese characters — a single character or a word
densitystringNominimal / full (default minimal). full adds families, explanation, examples, related words.
langstringNozh / en / ja / ko / vi / th / id / ru / es / fr / de / pt / ar (default zh) — see language coverage note below
variantstringNosimp / trad (default simp). Traditional-script compound words are auto-converted server-side if the exact input isn't indexed — see Best Practices.
Language coverage — read this before assuming every field is translated

Fixed-vocabulary fields — part-of-speech tags (pos) and the short semantic-component gloss (semantic.meaning_xx) — are properly translated for all 13 languages, using each language's own standard grammatical terminology (not machine translation). Free-text fields — explanation (etymology narrative), examples, and compound-word meaning — only have native Chinese and English versions upstream; for the other 11 languages these fields fall back to English (then Chinese if English isn't available). This is intentional, not a bug — see GET /v1/health for the exact machine-readable breakdown under known_limitations.

Response fields

The shape depends on input length. A single character: views.character (structure — semantic/phonetic components, families, etymology) plus views.word (this character used as a standalone word, sourced from a dedicated monosyllabic-word dictionary — not the character's etymological meaning). A word (2–4 characters): views.word only, with parts[] giving each component character's own dictionary sense. See the sample response above for the full shape.返回结构取决于输入长度。单字:views.character(结构——意符/声符、字族、造字理据)加上 views.word(把这个字当独立词看,来自专门的单字词词典,不是字的本义)。词语(2-4字):只有 views.word,附带 parts[] 给出每个字自己的词义。完整结构见上方示例响应。

Every response includes a meta block with request_id (a fresh UUID per call — even on cache hits — for support/log correlation) and lang_coverage ("full" for zh/en, "fixed_vocab_only" for the other 11 languages — lets you decide programmatically whether to show a "partial translation" hint in your own UI).每次响应都带一个 meta 区块,含 request_id(每次调用都是全新的 UUID,缓存命中也不例外,方便对日志/工单)和 lang_coverage(zh/en 是 "full",其余11种语言是 "fixed_vocab_only"——可以据此在自己的界面上决定要不要提示"部分内容未完整翻译")。

Error codes

CodeHTTPMeaning
4001400Invalid text — must be 1–4 Chinese characters only
4010401Missing, malformed, or invalid/revoked API key
4032403This key isn't enabled for Widget use
4033403Request origin isn't in the key's domain whitelist
4034403This key is scoped to Widget-only use and can't be called directly from a server
4290429Daily or monthly quota exceeded — see Pricing to upgrade
4291429Too many requests in a short window (burst protection, separate from quota) — wait a few seconds and retry
5000500Internal error — retry, or check /v1/health

Rate limits & usage

Each plan has a daily and monthly character quota — billed as a flat monthly fee, not per-character metering (see Pricing for why). Check current usage and manage your plan from your dashboard. You can also configure a webhook URL (on the Billing page) to get notified when usage crosses 80%, 95%, and 100% of your monthly quota — checked every 15 minutes, not instant, and each threshold fires at most once per billing period.每个套餐有每日和每月的字符额度——按固定月费计费,不是按字符实时扣费(原因见定价页)。当前用量和套餐管理在后台查看。也可以在 Billing 页配置一个 Webhook 地址,用量跨过每月配额的80%、95%、100%时会收到通知——每15分钟检查一次,不是实时的,每个阈值每个计费周期最多触发一次。

Batch requests

POST /v1/decompose/batch looks up multiple characters/words in one call — useful for annotating a whole vocabulary list instead of issuing one request per item. Same parameters as /v1/decompose, except text becomes texts (an array, max 50 items). One item failing (invalid input, not found) doesn't fail the batch — each result is tagged found: true/false independently.POST /v1/decompose/batch 一次调用查多个字/词——批量标注一份词表比逐条发请求更合适。参数跟 /v1/decompose 一样,只是 text 换成 texts(数组,最多50条)。某一条失败(无效输入/未收录)不会拖累整批,每条结果各自标 found: true/false

curl -X POST https://api.chinesekey.org/v1/decompose/batch \
  -H "Authorization: Bearer pk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"texts": ["清", "安静", "学习"], "density": "minimal", "lang": "en"}'
{
  "code": 0,
  "data": [
    { "text": "清", "found": true, "views": { ... } },
    { "text": "安静", "found": true, "views": { ... } },
    { "text": "学习", "found": true, "views": { ... } }
  ],
  "meta": { "source": "HanziPeek", "version": "2.0", "request_id": "...", "lang_coverage": "full" }
}

Embed with one line of code

Two separate widgets, each a single script tag — pick one or use both (see the live comparison). Both share the same API key and usage quota as direct API calls.两个独立的 Widget,各自一行代码——用哪个都行,也可以两个都用(见实时对比演示)。两个都跟直接调 API 共用同一个 Key 和额度。

WordPeek · peek.js

Auto-detects words vs. single characters and shows meaning, part of speech, word formation. Best default choice for reading/learning content.自动识别字与词,给出释义、词性、构词法。适合当作阅读/学习内容的默认选择。

<script src="https://chinesekey.org/peek.js"
        data-key="pk_live_..."
        data-density="minimal"></script>
AttributeValuesDefault
data-keyyour API keyrequired
data-densityminimal / fullminimal
data-variantsimp / tradsimp — set to trad for Traditional-script pages

GlyphPeek · peek-hanzi.js

Structure only — semantic/phonetic components and component families. No vocabulary content. For sites focused specifically on character etymology (calligraphy, radical study, 说文解字-style content).只做字理——意符/声符及其家族,不含任何词汇信息。适合专门做汉字结构/说文解字类内容的网站。

<script src="https://chinesekey.org/peek-hanzi.js"
        data-key="pk_live_..."></script>
AttributeValuesDefault
data-keyyour API keyrequired
data-variantsimp / tradsimp

Always fetches full density — component families are the point of this widget.这个 Widget 固定用完整密度请求——家族圆圈是它存在的意义。

FAQ

Does the widget affect page performance? Each script targets under 15KB gzipped, with card styles inlined so it never leaks into your page's own CSS. Shadow DOM keeps the popup fully isolated.

Is the same character always the same result? Yes — results are cached per session, so a given character/word/language combination always returns the same answer.

Can I run both widgets on the same page? Yes, but only one should be actively scanning at a time to avoid double-wrapping the same text — see the demo page source for the enable/disable pattern (window.WordPeek / window.GlyphPeek).

Use as an AI Tool

HanziPeek can be registered as a function/tool with common LLM providers. When a user asks about a character's structure, the model calls the tool and grounds its answer in verifiable, source-traceable dictionary data instead of guessing.

OpenAI & Claude examples

{
  "name": "decompose_hanzi",
  "description": "Get the structural decomposition (for a single character) or word-level breakdown (for a word) of Chinese text: semantic/phonetic components, part of speech, word formation.",
  "parameters": {
    "type": "object",
    "properties": {
      "text": { "type": "string", "description": "A single Chinese character or word (1-4 characters)" },
      "lang": { "type": "string", "enum": ["zh", "en", "ja", "ko", "vi", "th", "id", "ru", "es", "fr", "de", "pt", "ar"] }
    },
    "required": ["text"]
  }
}

This same JSON schema works as an OpenAI function definition or an Anthropic tool definition — pass it in your tools array and call api.chinesekey.org/v1/decompose when the model invokes it.

MCP server example

HanziPeek doesn't run its own hosted MCP server, but the same /v1/decompose endpoint drops into a minimal MCP server you host yourself — useful for Claude Desktop, Cursor, or any MCP-compatible client. A single-tool Python server using the official mcp SDK:

from mcp.server.fastmcp import FastMCP
import httpx

mcp = FastMCP("hanzipeek")

@mcp.tool()
async def decompose_hanzi(text: str, lang: str = "en") -> dict:
    """Structural decomposition of a Chinese character or word."""
    async with httpx.AsyncClient() as client:
        r = await client.post(
            "https://api.chinesekey.org/v1/decompose",
            headers={"Authorization": "Bearer pk_live_..."},
            json={"text": text, "lang": lang, "density": "full"},
        )
        return r.json()

if __name__ == "__main__":
    mcp.run()

Point your MCP client's config at this script (e.g. Claude Desktop's claude_desktop_config.json, or Cursor's MCP settings) and the model can call it like any other tool — no separate hosting required beyond wherever you run this script.

Best Practices

Handling "not found"

Match the UI state to the response: a legitimate Chinese character with no data returns {"code":0,"data":null,"known":false}, not an error. Reserve the error state for invalid input, invalid keys, and rate limits — don't render "not in this dataset" the same way you'd render a 500.

Caching

The same (text, density, lang, variant) combination always returns the same answer, so results are safe to cache client-side or at the CDN edge. The API itself also caches results server-side — repeat lookups of common characters are typically faster on the second call.

Traditional Chinese input

Single characters resolve in either script directly. For multi-character words, if the exact Traditional-script input isn't indexed, the server automatically retries against the Simplified form and converts the response back — see Request parameters.

SDK & Examples

No official SDK package yet — instead, a small example repository with working, copy-pasteable code: Python, JavaScript/Node, a zero-backend widget embed, a minimal React component, and an MCP server. github.com/2741448-ctrl/hanzipeek-examples目前还没有正式的 SDK 包——先提供一个示例仓库,里面是能直接跑的代码:Python、JavaScript/Node、零后端的 Widget 嵌入、最小 React 组件、MCP Server。github.com/2741448-ctrl/hanzipeek-examples

Changelog

VersionNotes
2026.09.02Added Webhook usage alerts (Billing page) — get notified at 80%/95%/100% of monthly quota. Dashboard: call log viewer (last 100 requests), editable domain whitelist per key, and a Widget-only key scope (error code 4034) for safer public embeds. Published a public examples repository (Python, JS/Node, widget embed, React, MCP server). Added an Enterprise contact form and a public status page.
2026.09.01Added request_id and lang_coverage to every response's meta. Added an MCP server example. Added POST /v1/decompose/batch for looking up up to 50 characters/words in one call. Removed an inaccurate "confidence score" claim from docs and marketing copy — this API returns deterministic dictionary lookups, not a probabilistic confidence metric.
2026.08.31Burst rate limiting (error code 4291) and result caching added to protect shared infrastructure. Failed-payment email notifications added.
2026.08.31Self-serve billing: Free / Starter / Growth / Pro plans via Stripe, managed from the dashboard.
2026.08.31Passwordless sign-in and self-serve API key management dashboard.
2026.08.31Added lang support for ja / ko / vi / th / id / ru / es / fr / de / pt / ar (part-of-speech and semantic-component fields).
2026.08.30Traditional Chinese (variant=trad) fixed for compound words — auto-converts and localizes via OpenCC.
2026.08Public documentation and widget release for chinesekey.org.

Don't have a key yet?

Get API Key