{
 "schemaVersion": 1,
 "stability": {
  "promise": "Keys listed here are frozen for the life of /api/v1/. Keys may be ADDED to v1. None is ever removed, renamed or retyped — a change that would break a reader gets /api/v2/ at a different address, and v1 keeps running beside it for at least twelve months after v2 opens.",
  "lockedBy": "tests/test_api.py, which fails the build if this drifts",
  "versionIn": "the URL path, not a header"
 },
 "envelope": [
  "schemaVersion",
  "generated",
  "query",
  "total",
  "count",
  "limit",
  "offset",
  "results",
  "attribution",
  "licence",
  "terms"
 ],
 "result": {
  "always": [
   "id",
   "url",
   "apiUrl",
   "province",
   "name",
   "nameEn",
   "categories",
   "subcategories",
   "lat",
   "lng",
   "geoPrecision",
   "hours",
   "openNow",
   "antRank",
   "has",
   "tags",
   "lenses",
   "facets",
   "confidence",
   "osmDerived",
   "updatedAt",
   "photoUrl"
  ],
  "conditional": {
   "distanceM": "only when near= was given"
  },
  "nullMeansUnknown": [
   "openNow — null when nobody holds this place's hours. Never false-because-unknown.",
   "lat / lng — null when the place is known but not yet pinned; geoPrecision says which.",
   "nameEn, hours, updatedAt — null when the record does not carry one."
  ]
 },
 "bulkIndexRow": {
  "keys": [
   "id",
   "slug",
   "province",
   "name",
   "nameEn",
   "cat",
   "sub",
   "lat",
   "lng",
   "geoPrecision",
   "antRank",
   "has",
   "hours",
   "sched",
   "tags",
   "lenses",
   "facets",
   "confidence",
   "osmDerived",
   "updatedAt",
   "photo",
   "q"
  ],
  "omissionRule": "A row OMITS any key whose value would be null or an empty list. Absent means unknown or none — it never means false. `sched` indexes the top-level `schedules` table; absent means unknown hours."
 },
 "vocabularies": {
  "has": [
   "nameTh",
   "nameEn",
   "phone",
   "line",
   "hours",
   "web",
   "photo",
   "claimed",
   "fresh"
  ],
  "geoPrecision": [
   "exact",
   "block",
   "approx",
   "needs-pin"
  ],
  "province": [
   "cm",
   "cr"
  ],
  "sort": [
   "distance",
   "ants",
   "name",
   "relevance"
  ],
  "liveKeys": "https://motdang.net/api/v1/tags"
 },
 "fullRecord": {
  "url": "https://motdang.net/api/v1/places/{idOrSlug}",
  "note": "The full record is the place page's own .json sibling, which carries every field including sources, channels, retiredLinks, antBits, facets, lenses and licence. Its optional keys follow the same omission rule."
 },
 "terms": "https://motdang.net/terms.html",
 "attribution": "มดแดง Mot Dang · motdang.net"
}