{
 "endpoint": "/api/query",
 "how": "GET /api/query?sql=<url-encoded SQL> — works with any fetch tool, including one that cannot POST. Or POST {\"sql\": \"SELECT ...\", \"params\": []} if you can.",
 "limits": {
  "rate": "About ten requests per ten seconds per IP. A fourth is refused by the edge with HTTP 429 and a seventeen-byte body reading `error code: 1015` — that is a rate limit, not an error and not a gap in the data. Wait ten seconds.",
  "daily": "This endpoint computes on request and has a daily usage limit. Static files have none.",
  "unlimited": "https://lunenburgbudgetproject.org/api/tables and everything it lists are static and never limited."
 },
 "rules": [
  "One statement. It must start with SELECT or WITH.",
  "A LIMIT is added if you omit one, and capped at 1000 rows.",
  "Use ? placeholders and pass `params`; values are bound, never interpolated."
 ],
 "readFirst": "https://lunenburgbudgetproject.org/api/schema",
 "tables": "https://lunenburgbudgetproject.org/api/tables",
 "example": {
  "sql": "SELECT fy, COUNT(*) AS paras FROM staff_roster_entries WHERE position = 'Paraprofessional' AND grade_or_dept LIKE ? GROUP BY fy ORDER BY fy",
  "params": [
   "%indergarten%"
  ]
 },
 "provenance": "Join `dataset_document` to keep the address of the document a row came from: JOIN dataset_document d ON d.dataset = 'report-appropriations' AND d.edition = r.edition. Without it a result has no route back to a source, and this endpoint will say so."
}
