{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://plainlanguage.us/kit/field-schema.json",
  "title": "PlainLanguage.us API v1 — response field schema",
  "description": "Every product-surface response shape (API contract v1, as amended by the product split 2026-07-14). Generated from the same captured fixtures that drive the site's offline mock; regenerated on every site build, validated against the fixtures, so it cannot drift.",
  "$defs": {
    "Match": {
      "type": "object",
      "description": "One found legal term. start/end are UTF-16 code-unit offsets into exactly the text you sent (safe for JavaScript slice; code-point languages count differently once text contains astral characters). Matches can nest; render the longest non-overlapping spans.",
      "required": [
        "termId",
        "surface",
        "kinds",
        "start",
        "end",
        "tokens",
        "plainLanguage"
      ],
      "properties": {
        "termId": {
          "type": "integer",
          "description": "Card id for GET /v1/term/:id"
        },
        "surface": {
          "type": "string",
          "description": "The canonical matched term"
        },
        "kinds": {
          "type": "array",
          "items": {
            "enum": [
              "headword",
              "subtype",
              "word_sub",
              "override"
            ]
          },
          "description": "How the term matched (one or more)"
        },
        "start": {
          "type": "integer"
        },
        "end": {
          "type": "integer"
        },
        "tokens": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "plainLanguage": {
          "type": [
            "string",
            "null"
          ],
          "description": "The curated rendering; null = known term with no paraphrase yet (rare; still costs like any match)"
        }
      }
    },
    "TranslateResponse": {
      "type": "object",
      "description": "POST /v1/translate (and /phase1, /phase2). Cost: matchCount.",
      "required": [
        "phase",
        "tokenCount",
        "matchCount",
        "substitutionCount",
        "elapsedMs",
        "matches"
      ],
      "properties": {
        "phase": {
          "const": 2
        },
        "tokenCount": {
          "type": "integer",
          "description": "Word tokens the matcher saw (letters-only tokenization)"
        },
        "matchCount": {
          "type": "integer",
          "description": "THE COST: term matches found = units charged"
        },
        "substitutionCount": {
          "type": "integer",
          "description": "Matches carrying a plainLanguage suggestion"
        },
        "opsBilled": {
          "type": "integer",
          "description": "Developer keys only: what this request just cost in operations (= matchCount here). Absent on workspace keys."
        },
        "elapsedMs": {
          "type": "number",
          "description": "Coarsened at the edge, often 0; don't build on it"
        },
        "matches": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Match"
          }
        }
      }
    },
    "UsageWorkspace": {
      "type": "object",
      "description": "GET /v1/usage on a workspace key: term matches against the monthly cap.",
      "required": [
        "tier",
        "cap",
        "used",
        "remaining",
        "periodStart",
        "periodEnd"
      ],
      "properties": {
        "tier": {
          "const": "workspace"
        },
        "cap": {
          "type": "integer"
        },
        "used": {
          "type": "integer"
        },
        "remaining": {
          "type": "integer"
        },
        "periodStart": {
          "type": "string"
        },
        "periodEnd": {
          "type": "string"
        }
      }
    },
    "UsageDeveloper": {
      "type": "object",
      "description": "GET /v1/usage on a developer key: the period's billed operations. cap/remaining are null (uncapped); estimatedCost = used x 0.0025 USD, an estimate (the Stripe invoice is authoritative).",
      "required": [
        "tier",
        "cap",
        "used",
        "remaining",
        "estimatedCost",
        "periodStart",
        "periodEnd"
      ],
      "properties": {
        "tier": {
          "const": "developer"
        },
        "cap": {
          "type": "null"
        },
        "used": {
          "type": "integer"
        },
        "remaining": {
          "type": "null"
        },
        "estimatedCost": {
          "type": "number"
        },
        "periodStart": {
          "type": "string"
        },
        "periodEnd": {
          "type": "string"
        }
      }
    },
    "UsageResponse": {
      "oneOf": [
        {
          "$ref": "#/$defs/UsageWorkspace"
        },
        {
          "$ref": "#/$defs/UsageDeveloper"
        }
      ]
    },
    "SectionProseChips": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type",
        "text"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "prose+chips"
        },
        "text": {
          "type": "string"
        },
        "chips": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "SectionBulletsProse": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "bullets+prose"
        },
        "bullets": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "notes": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "SectionProse": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type",
        "text"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "prose"
        },
        "text": {
          "type": "string"
        }
      }
    },
    "SectionContextList": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type",
        "items"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "contextList"
        },
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "context"
            ],
            "properties": {
              "context": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "meaning": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "plainLanguage": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      }
    },
    "SectionSubtypeList": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type",
        "items"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "subtypeList"
        },
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "definition": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "plainLanguage": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      }
    },
    "SectionLegalPlainPairs": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type",
        "items"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "legalPlainPairs"
        },
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "legal",
              "plain"
            ],
            "properties": {
              "legal": {
                "type": "string"
              },
              "plain": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "SectionChipGroups": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "chipGroups"
        },
        "contexts": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "domains": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "SectionTermLinks": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type",
        "items"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "termLinks"
        },
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "label"
            ],
            "properties": {
              "label": {
                "type": "string"
              },
              "termId": {
                "type": "integer"
              }
            }
          }
        }
      }
    },
    "SectionFacts": {
      "type": "object",
      "required": [
        "id",
        "label",
        "defaultOpen",
        "type"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "defaultOpen": {
          "type": "boolean"
        },
        "type": {
          "const": "facts"
        },
        "pronunciation": {
          "type": [
            "string",
            "null"
          ]
        },
        "partOfSpeech": {
          "type": [
            "string",
            "null"
          ]
        },
        "frequency": {
          "type": [
            "string",
            "null"
          ]
        },
        "formality": {
          "type": [
            "string",
            "null"
          ]
        },
        "readabilityLevel": {
          "type": [
            "string",
            "null"
          ]
        },
        "etymology": {
          "type": [
            "object",
            "null"
          ],
          "properties": {
            "origin": {
              "type": [
                "string",
                "null"
              ]
            },
            "literalMeaning": {
              "type": [
                "string",
                "null"
              ]
            },
            "firstLegalUse": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        }
      }
    },
    "TermSection": {
      "description": "Server-driven card panel. The 9 section ids, in canonical order: plain, watch, definition, byContext, subtypes, examples, contexts, related, word. Terms carry 7-9 in practice (empty sections are omitted). Render what you receive; skip types you don't know.",
      "oneOf": [
        {
          "$ref": "#/$defs/SectionProseChips"
        },
        {
          "$ref": "#/$defs/SectionBulletsProse"
        },
        {
          "$ref": "#/$defs/SectionProse"
        },
        {
          "$ref": "#/$defs/SectionContextList"
        },
        {
          "$ref": "#/$defs/SectionSubtypeList"
        },
        {
          "$ref": "#/$defs/SectionLegalPlainPairs"
        },
        {
          "$ref": "#/$defs/SectionChipGroups"
        },
        {
          "$ref": "#/$defs/SectionTermLinks"
        },
        {
          "$ref": "#/$defs/SectionFacts"
        }
      ]
    },
    "TermDetail": {
      "type": "object",
      "description": "GET /v1/term/:id[?sections=...]. ?sections= filters to named panels (comma-separated ids; unknown id = 400). Workspace keys: free. Developer keys: 1 operation per section actually returned, echoed in opsBilled.",
      "required": [
        "termId",
        "term",
        "slug",
        "sections"
      ],
      "properties": {
        "termId": {
          "type": "integer"
        },
        "term": {
          "type": "string"
        },
        "slug": {
          "type": [
            "string",
            "null"
          ]
        },
        "opsBilled": {
          "type": "integer",
          "description": "Developer keys only: sections returned = operations billed"
        },
        "sections": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TermSection"
          }
        }
      }
    },
    "GlossaryEntry": {
      "type": "object",
      "required": [
        "term",
        "plainLanguage"
      ],
      "properties": {
        "term": {
          "type": "string"
        },
        "plainLanguage": {
          "type": "string"
        },
        "pitfalls": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "definition": {
          "type": "string"
        },
        "alternateMeanings": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "context": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "plainLanguage": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      }
    },
    "PromptExport": {
      "type": "object",
      "required": [
        "grounding",
        "glossary",
        "prompt",
        "messages"
      ],
      "properties": {
        "grounding": {
          "enum": [
            "minimal",
            "standard",
            "rich"
          ]
        },
        "glossary": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/GlossaryEntry"
          }
        },
        "prompt": {
          "type": "string",
          "description": "Ready to paste into any chat model"
        },
        "messages": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "role",
              "content"
            ],
            "properties": {
              "role": {
                "enum": [
                  "system",
                  "user"
                ]
              },
              "content": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "Phase3Response": {
      "type": "object",
      "description": "POST /phase3: everything /v1/translate returns plus promptExport. refined:false is permanent (no model runs here). Workspace cost: matchCount. Developer cost: matchCount + distinct embedded terms x {minimal 0, standard 1, rich 3}.",
      "required": [
        "phase",
        "refined",
        "tokenCount",
        "matchCount",
        "substitutionCount",
        "elapsedMs",
        "matches",
        "promptExport"
      ],
      "properties": {
        "phase": {
          "const": 3
        },
        "refined": {
          "const": false
        },
        "tokenCount": {
          "type": "integer"
        },
        "matchCount": {
          "type": "integer"
        },
        "substitutionCount": {
          "type": "integer"
        },
        "opsBilled": {
          "type": "integer",
          "description": "Developer keys only"
        },
        "elapsedMs": {
          "type": "number"
        },
        "matches": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Match"
          }
        },
        "promptExport": {
          "$ref": "#/$defs/PromptExport"
        }
      }
    },
    "ErrorBody": {
      "type": "object",
      "description": "Every non-2xx is JSON {error, ...}. Stable extras per case: status on 403, tier/cap/used/requested on 429.",
      "required": [
        "error"
      ],
      "properties": {
        "error": {
          "type": "string"
        }
      }
    },
    "KeyRollResponse": {
      "type": "object",
      "required": [
        "apiKey",
        "note"
      ],
      "properties": {
        "apiKey": {
          "type": "string"
        },
        "note": {
          "type": "string"
        }
      }
    },
    "KeyRevokeResponse": {
      "type": "object",
      "required": [
        "ok",
        "note"
      ],
      "properties": {
        "ok": {
          "type": "boolean"
        },
        "note": {
          "type": "string"
        }
      }
    },
    "Health": {
      "type": "object",
      "required": [
        "ok",
        "service",
        "contract"
      ],
      "properties": {
        "ok": {
          "type": "boolean"
        },
        "service": {
          "type": "string"
        },
        "contract": {
          "type": "string"
        }
      }
    }
  }
}