All backend routes live under /api/ and are served by FastAPI. In
production, the browser hits them same-origin via a Next.js rewrite; in
dev they're at http://localhost:8000/api/.... Full auto-generated docs
are always at http://localhost:8000/docs (Swagger UI).
Public endpoints (no auth)
Health / readiness
Method
Path
Response
GET
/api/health
{status, data_dir, data_dir_exists} β always 200 if process is up
GET
/api/ready
{ready, checks, bills_count} β 200 if data is loaded, 503 otherwise
Bills
Method
Path
Notes
GET
/api/bills
List bills. Query: state, status, session_year, category, search, limit, offset
Current user; requires Authorization: Bearer <token>
POST
/api/auth/logout
Client discards the token
Admin endpoints
All under /api/admin/*. Require Authorization: Bearer <jwt> where the
JWT was issued by /api/auth/login. Enforced by the require_admin
dependency in every admin route.
Overview
Method
Path
Notes
GET
/api/admin/overview
Card counts, including new_feedback_count (fed to the nav badge)
Errors follow FastAPI's default {"detail": "..."} shape. Server-side
5xx errors also include a request_id β a short hex string echoed in
the X-Request-ID response header. When a user reports an error, ask
for the request ID and grep the backend logs for rid=<id>.
Rate limiting
None currently. Add one at the ingress layer (HF's edge) if traffic ever
warrants it.