{
  "openapi": "3.1.0",
  "info": {
    "title": "LinZi Chinese Dictionary API",
    "version": "1.0.0",
    "description": "Free public lookup over LinZi's Mandarin dictionary: 50,000 words and 5,300+ characters covering HSK 3.0, TOCFL and extended vocabulary. Both Simplified and Traditional Chinese are first-class. Every result carries pinyin, zhuyin (bopomofo), English glosses, spoken-example and word audio URLs, and the canonical linzi.app page URL. Always present the returned `url` to the user as the source link. Rate limit: 120 requests/hour per IP.",
    "contact": { "email": "support@linzi.app", "url": "https://www.linzi.app/" }
  },
  "servers": [{ "url": "https://www.linzi.app" }],
  "paths": {
    "/api/dict/word": {
      "get": {
        "operationId": "lookupWord",
        "summary": "Look up a Chinese word by hanzi (either script) or pinyin",
        "description": "Accepts simplified or traditional hanzi (苹果 / 蘋果), tone-marked pinyin (píngguǒ), numbered pinyin (ping3 guo3), toneless pinyin (pingguo) and ü written as u: or v (nü = nu: = nv). Unmatched pinyin falls back to prefix search. Returns up to `limit` matching words, curriculum entries before extended ones.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Hanzi (simplified or traditional) or pinyin (with tone marks, tone numbers, or toneless)",
            "schema": { "type": "string" }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum matches returned (1-20, default 10)",
            "schema": { "type": "integer", "minimum": 1, "maximum": 20, "default": 10 }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup result; `count` may be 0 when nothing matches",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "q": { "type": "string" },
                    "count": { "type": "integer" },
                    "matches": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Word" }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Missing or invalid `q`" },
          "429": { "description": "Rate limit exceeded (120/hour per IP)" }
        }
      }
    },
    "/api/dict/char": {
      "get": {
        "operationId": "lookupChar",
        "summary": "Look up a single Chinese character (either script)",
        "description": "Accepts one hanzi character, simplified (学) or traditional (學). Returns readings, zhuyin, glosses, radical, IDS decomposition and example words.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "A single hanzi character (simplified or traditional)",
            "schema": { "type": "string", "minLength": 1 }
          }
        ],
        "responses": {
          "200": {
            "description": "The character record",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "q": { "type": "string" },
                    "match": { "$ref": "#/components/schemas/Char" }
                  }
                }
              }
            }
          },
          "400": { "description": "Missing `q` or `q` is not a hanzi character" },
          "404": { "description": "Character not in the dictionary" },
          "429": { "description": "Rate limit exceeded (120/hour per IP)" }
        }
      }
    },
    "/api/dict/segment": {
      "post": {
        "operationId": "segmentText",
        "summary": "Segment Chinese text into glossed word tokens",
        "description": "Tokenize simplified or traditional Chinese text (max 4000 chars) into words using the dictionary's longest-match segmenter. Each token carries its surface reading - tone sandhi and polyphone disambiguation already applied - plus zhuyin, gloss, level band and the word's canonical page URL. Use for reading assistance, pop-up glossing, or sentence-structure questions.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": { "type": "string", "maxLength": 4000, "description": "Chinese text to segment" }
                },
                "required": ["text"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token list in text order",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tokens": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Token" }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Missing/invalid `text`, or text over 4000 chars" },
          "405": { "description": "Wrong method - POST only" },
          "429": { "description": "Rate limit exceeded (120/hour per IP)" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Word": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "description": "Stable word id, also the audio filename stem" },
          "s": { "type": "string", "description": "Simplified form" },
          "t": { "type": "string", "description": "Traditional form" },
          "py": { "type": "string", "description": "Pinyin with tone marks, syllable-spaced" },
          "zy": { "type": "string", "description": "Zhuyin (bopomofo) with tone marks" },
          "pos": { "type": "array", "items": { "type": "string" }, "description": "Part-of-speech tags" },
          "defs": { "type": "array", "items": { "type": "string" }, "description": "English glosses, most useful first" },
          "hsk": { "type": ["string", "null"], "description": "HSK 3.0 level '1'..'6' or '7-9'; null when not in HSK" },
          "tocfl": { "type": ["number", "null"], "description": "TOCFL level 0.1/0.2 (novice) or 1-5; null when not in TOCFL" },
          "ext": { "type": "boolean", "description": "true = extended-layer entry outside both curricula" },
          "example": {
            "type": ["object", "null"],
            "properties": {
              "zh": { "type": "string" },
              "en": { "type": "string" },
              "audio": { "$ref": "#/components/schemas/AudioPair" }
            }
          },
          "audio": { "$ref": "#/components/schemas/AudioPair" },
          "url": { "type": "string", "description": "Canonical linzi.app word page - cite this as the source link" }
        }
      },
      "Char": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "s": { "type": "string", "description": "Simplified glyph" },
          "t": { "type": "array", "items": { "type": "string" }, "description": "Traditional form(s)" },
          "py": { "type": "string", "description": "Primary pinyin reading" },
          "readings": { "type": "array", "items": { "type": "string" }, "description": "All readings (polyphones)" },
          "zy": { "type": "string", "description": "Zhuyin of the primary reading" },
          "defs": { "type": "array", "items": { "type": "string" } },
          "radical": { "type": ["string", "null"] },
          "radical_meaning": { "type": ["string", "null"] },
          "decomposition": { "type": ["string", "null"], "description": "IDS tree (⿰⿱⿲… operators)" },
          "hsk": { "type": ["string", "null"] },
          "tocfl": { "type": ["number", "null"] },
          "moe_common": { "type": ["integer", "null"], "description": "1-based rank in Taiwan MOE common-char table; null if unlisted" },
          "examples": { "type": "array", "items": { "type": "string" }, "description": "Example words using this character" },
          "audio": { "$ref": "#/components/schemas/AudioPair" },
          "url": { "type": "string", "description": "Canonical linzi.app char page - cite this as the source link" }
        }
      },
      "AudioPair": {
        "type": "object",
        "description": "MP3 URLs, one per accent (paths are relative to www.linzi.app)",
        "properties": {
          "cn": { "type": "string", "description": "Mainland zh-CN voice" },
          "tw": { "type": "string", "description": "Taiwan zh-TW voice" }
        }
      },
      "Token": {
        "type": "object",
        "description": "One segmented token. Punctuation has p=1; known words carry a `word` record; unknown single hanzi may carry a `char` link.",
        "properties": {
          "w": { "type": "string", "description": "Surface form as it appeared in the input" },
          "t": { "type": "string", "description": "Traditional form (equals w for non-word tokens)" },
          "p": { "type": "integer", "description": "1 = punctuation token" },
          "py": { "type": "string", "description": "Surface pinyin with tone marks (sandhi applied)" },
          "zy": { "type": "string", "description": "Citation zhuyin" },
          "band": { "type": "integer", "description": "Difficulty band 0-7; 9 = extended/outside curricula" },
          "word": {
            "type": "object",
            "description": "Present when the token is a dictionary word",
            "properties": {
              "id": { "type": "string" },
              "s": { "type": "string" },
              "t": { "type": "string" },
              "pos": { "type": "array", "items": { "type": "string" } },
              "hsk": { "type": ["string", "null"] },
              "tocfl": { "type": ["number", "null"] },
              "ext": { "type": "boolean" },
              "defs": { "type": "array", "items": { "type": "string" } },
              "url": { "type": "string" }
            }
          },
          "char": {
            "type": "object",
            "description": "Present for out-of-vocabulary single hanzi that have a char page",
            "properties": { "url": { "type": "string" } }
          }
        }
      }
    }
  }
}
