Docs · Understand
API reference
Authenticated, organization-scoped REST. Every mounted route is described by a live OpenAPI 3.1 document, and a CI test fails if a route ships without a spec entry.
Authentication
Better Auth issues an HTTP-only session cookie on sign-in. Browser clients just work (same-origin or CORS-enabled); non-browser clients pass the session cookie with each request. Sign-up requires an Origin header matching a trusted origin — a deliberate CSRF guard.
curl -X POST http://localhost:4000/api/auth/sign-in/email \
-H "content-type: application/json" \
-H "Origin: http://localhost:3000" \
-d '{"email":"you@example.com","password":"..."}' -c cookies.txt
curl http://localhost:4000/api/jobs -b cookies.txtThe contract
Fetch GET /api/openapi.json from a running instance for the authoritative, live spec — every route, shape, error envelope, and auth requirement.
Routes
| Method | Path | What it does |
|---|---|---|
GET | /api/health | Public health check |
POST | /api/auth/sign-up/email | Register (Better Auth) |
POST | /api/auth/sign-in/email | Log in |
GET|POST|PATCH | /api/jobs | Jobs CRUD (org-scoped) |
GET|POST | /api/jobs/:id/rubrics | Rubric versions |
POST | /api/jobs/:id/rubrics/derive | LLM JD → criteria |
POST | /api/jobs/:id/candidates | Upload a resume (PDF/DOCX/TXT/MD) |
POST | /api/jobs/:id/candidates/zip | Batch-upload a ZIP of resumes |
POST | /api/jobs/:id/score | Score all candidates (concurrency-bounded, audited) |
GET | /api/jobs/:id/runs | Scoring run history |
GET | /api/jobs/:id/runs/:runId | Run detail: per-candidate scores + evidence spans |
GET | /api/jobs/:id/candidates | Candidate list (metadata only — no resume text) |
GET | /api/jobs/:id/candidates/:cid | Candidate detail: parsed profile, document text, decisions |
GET | /api/jobs/:id/review | Ranked review table: latest overall per candidate + stage |
POST | /api/jobs/:id/decisions | Record a decision (stage + required reason; audit-chained) |
PATCH | /api/jobs/:id/scores/:scoreId | Manual score override (author + reason recorded) |
PUT | /api/jobs/:id/demographics/:cid | Candidate's opt-in demographics self-report |
POST | /api/jobs/:id/bias-audit | Adverse-impact report (four-fifths rule; audited) |
GET | /api/openapi.json | The live OpenAPI 3.1 contract |
Error envelope
All errors share one shape:
{ "error": { "code": "llm_not_configured", "message": "..." } }Typed error codes (like 401 sign_in_failed, 503 llm_not_configured) are stable — build against them, not against message text.