openapi: 3.1.0
info:
  title: THE TEA — Content API
  version: "2.0"
  description: >
    Free, open, read-only REST API for a granular encyclopedia of Chinese tea:
    482 teas described across 72 languages, decomposed into queryable fields
    (taste, brewing, terroir, chemistry, sensory profiles, recipes, harvest, coordinates).
    See API_REFERENCE.md for the full guide.
  license:
    name: CC BY-NC-SA (content, preview) — see /api/v2 docs
    url: https://thetea.app
  contact:
    name: THE TEA
    url: https://thetea.app
servers:
  - url: https://api.thetea.app
tags:
  - name: teas
  - name: discovery
  - name: reference
paths:
  /api/v2/tea/{slug}:
    get:
      tags: [teas]
      summary: Full tea card (meta + fields + sensory + recipe + harvest + names + tags + enrichment + seo)
      parameters:
        - { name: slug, in: path, required: true, schema: { type: string }, example: biluochun }
        - { name: lang, in: query, schema: { type: string, default: en }, example: ru }
      responses:
        "200": { description: OK, content: { application/json: { schema: { $ref: "#/components/schemas/TeaCard" } } } }
        "404": { description: Not found }
  /api/v2/tea/{slug}.md:
    get:
      tags: [teas]
      summary: Full tea card rendered as Markdown
      parameters:
        - { name: slug, in: path, required: true, schema: { type: string } }
        - { name: lang, in: query, schema: { type: string, default: en } }
      responses:
        "200": { description: Markdown, content: { text/markdown: { schema: { type: string } } } }
  /api/v2/tea/{slug}/{lang}/field/{code}:
    get:
      tags: [teas]
      summary: A single field value
      parameters:
        - { name: slug, in: path, required: true, schema: { type: string } }
        - { name: lang, in: path, required: true, schema: { type: string } }
        - { name: code, in: path, required: true, schema: { type: string }, example: water_temp }
      responses:
        "200": { description: OK, content: { application/json: { schema: { $ref: "#/components/schemas/Field" } } } }
        "404": { description: Not found }
  /api/v2/teas:
    get:
      tags: [discovery]
      summary: Filtered list of teas
      parameters:
        - { name: tea_type, in: query, schema: { type: string, enum: [green, white, yellow, oolong, red, dark, puer] } }
        - { name: country, in: query, schema: { type: string }, example: CN }
        - { name: province, in: query, schema: { type: string }, example: Fujian }
        - { name: brew_temp_max, in: query, schema: { type: integer }, example: 80 }
        - { name: altitude_min, in: query, schema: { type: integer }, example: 1500 }
        - { name: hasCoords, in: query, schema: { type: string, enum: ["1"] } }
        - { name: tag, in: query, schema: { type: string }, example: ten-famous-teas }
        - { name: q, in: query, schema: { type: string } }
        - { name: lang, in: query, schema: { type: string, default: en } }
        - { name: limit, in: query, schema: { type: integer, default: 100, maximum: 500 } }
        - { name: offset, in: query, schema: { type: integer, default: 0 } }
      responses:
        "200": { description: OK, content: { application/json: { schema: { $ref: "#/components/schemas/TeaList" } } } }
  /api/v2/search:
    get:
      tags: [discovery]
      summary: Multilingual search (Cyrillic / Hanzi / pinyin / Latin)
      parameters:
        - { name: q, in: query, required: true, schema: { type: string }, example: билочунь }
        - { name: lang, in: query, schema: { type: string, default: en } }
        - { name: limit, in: query, schema: { type: integer, default: 30, maximum: 200 } }
      responses:
        "200": { description: OK }
        "400": { description: q required }
  /api/v2/map:
    get:
      tags: [discovery]
      summary: All teas with coordinates (map layer)
      parameters: [ { name: lang, in: query, schema: { type: string, default: en } } ]
      responses: { "200": { description: OK } }
  /api/v2/random:
    get:
      tags: [discovery]
      summary: A random tea card (tea of the moment)
      parameters: [ { name: lang, in: query, schema: { type: string, default: en } } ]
      responses: { "200": { description: OK } }
  /api/v2/semantic:
    get:
      tags: [discovery]
      summary: Natural-language / "by vibe" semantic search (Vectorize + bge-m3; works in any language)
      parameters:
        - { name: q, in: query, required: true, schema: { type: string }, example: "smoky oolong with caramel" }
        - { name: tea_type, in: query, schema: { type: string, enum: [green, white, yellow, oolong, red, dark, puer] } }
        - { name: province, in: query, schema: { type: string }, example: Fujian }
        - { name: lang, in: query, schema: { type: string, default: en } }
        - { name: limit, in: query, schema: { type: integer, default: 10, maximum: 50 } }
      responses: { "200": { description: OK }, "400": { description: q required } }
  /api/v2/ask:
    get:
      tags: [discovery]
      summary: AI sommelier — grounded natural-language answer + recommended teas (RAG; Vectorize + Workers AI LLM)
      parameters:
        - { name: q, in: query, required: true, schema: { type: string }, example: "a smoky oolong for a cold evening" }
        - { name: lang, in: query, schema: { type: string, default: en } }
      responses: { "200": { description: "OK — { answer, sources[] }" }, "400": { description: q required } }
  /api/v2/tea/{slug}/similar:
    get:
      tags: [discovery]
      summary: Teas most similar to this one (nearest by sensory/semantic vector)
      parameters:
        - { name: slug, in: path, required: true, schema: { type: string }, example: da-hong-pao }
        - { name: lang, in: query, schema: { type: string, default: en } }
        - { name: limit, in: query, schema: { type: integer, default: 6, maximum: 50 } }
      responses: { "200": { description: OK }, "404": { description: no vector for slug } }
  /api/v2/compare:
    get:
      tags: [discovery]
      summary: Compare 2–5 teas side by side on key fields
      parameters:
        - { name: slugs, in: query, required: true, schema: { type: string }, example: "biluochun,xihu-longjing" }
        - { name: lang, in: query, schema: { type: string, default: en } }
      responses: { "200": { description: OK }, "400": { description: slugs required } }
  /api/v2/glossary:
    get:
      tags: [reference]
      summary: Multilingual tea terminology (2623 terms)
      parameters:
        - { name: lang, in: query, schema: { type: string, default: en } }
        - { name: category, in: query, schema: { type: string }, example: tasting }
        - { name: q, in: query, schema: { type: string } }
        - { name: limit, in: query, schema: { type: integer, default: 100, maximum: 500 } }
      responses: { "200": { description: OK } }
  /api/v2/family:
    get: { tags: [reference], summary: Named tea families (taxonomy), responses: { "200": { description: OK } } }
  /api/v2/meta:
    get: { tags: [reference], summary: Locale (72) and country (25) registries, responses: { "200": { description: OK } } }
components:
  schemas:
    Field:
      type: object
      properties:
        value_md: { type: string }
        value_num: { type: [number, "null"] }
        unit: { type: [string, "null"] }
        section_code: { type: string }
    TeaList:
      type: object
      properties:
        count: { type: integer }
        offset: { type: integer }
        items:
          type: array
          items:
            type: object
            properties:
              slug: { type: string }
              tea_type: { type: string }
              origin_country: { type: string }
              province: { type: [string, "null"] }
              lat: { type: [number, "null"] }
              lng: { type: [number, "null"] }
              brew_temp_min: { type: [integer, "null"] }
              brew_temp_max: { type: [integer, "null"] }
              name: { type: [string, "null"] }
    TeaCard:
      type: object
      properties:
        slug: { type: string }
        kind: { type: string, enum: [tea, category] }
        lang: { type: string }
        name: { type: string }
        meta: { type: object, description: language-neutral facts (tea_type, oxidation, shape, coords, brew_temp, gi_status, province…) }
        names: { type: object, additionalProperties: { type: string }, description: name in each of 72 languages }
        sections:
          type: object
          description: "section_code -> { field_code -> { value, num?, unit?, source?, review? } }"
        sensory:
          type: array
          items: { type: object, properties: { descriptor_id: {type: string}, descriptor: {type: string}, intensity: {type: integer} } }
        recipe:
          type: array
          items: { type: object, properties: { style: {type: string}, water_temp: {type: integer}, tea_grams: {type: number}, water_ml: {type: integer}, steep_sec: {type: integer}, max_steeps: {type: integer}, rinse: {type: integer} } }
        harvest:
          type: array
          items: { type: object, properties: { phase: {type: string}, months: {type: string} } }
        tags: { type: array, items: { type: string } }
        comparison:
          type: array
          items: { type: object, properties: { other_slug: {type: string}, other_name: {type: string}, differences_md: {type: string} } }
        enrichment:
          type: object
          description: "AI-generated per-tea enrichment, localized to the requested language (code fields are language-neutral)."
          properties:
            caffeine_level: { type: string, enum: [low, medium, high] }
            difficulty: { type: string, enum: [beginner, intermediate, advanced] }
            price_tier: { type: string, enum: [budget, mid, premium] }
            best_season: { type: array, items: { type: string } }
            occasion: { type: array, items: { type: string } }
            flavor_tags: { type: array, items: { type: string }, description: "controlled flavor vocabulary (chestnut, orchid, umami…)" }
            similar_teas: { type: array, items: { type: string }, description: "slugs of similar teas" }
            one_liner: { type: string }
            summary: { type: string }
            tasting_note: { type: string }
            food_pairings: { type: array, items: { type: string } }
            faq:
              type: array
              items: { type: object, properties: { q: {type: string}, a: {type: string} } }
        seo:
          type: object
          description: "Localized SEO metadata for the tea, in the requested language."
          properties:
            title: { type: string }
            description: { type: string }
            keywords: { type: array, items: { type: string } }
