HireLens

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.txt

The contract

Fetch GET /api/openapi.json from a running instance for the authoritative, live spec — every route, shape, error envelope, and auth requirement.

Routes

MethodPathWhat it does
GET/api/healthPublic health check
POST/api/auth/sign-up/emailRegister (Better Auth)
POST/api/auth/sign-in/emailLog in
GET|POST|PATCH/api/jobsJobs CRUD (org-scoped)
GET|POST/api/jobs/:id/rubricsRubric versions
POST/api/jobs/:id/rubrics/deriveLLM JD → criteria
POST/api/jobs/:id/candidatesUpload a resume (PDF/DOCX/TXT/MD)
POST/api/jobs/:id/candidates/zipBatch-upload a ZIP of resumes
POST/api/jobs/:id/scoreScore all candidates (concurrency-bounded, audited)
GET/api/jobs/:id/runsScoring run history
GET/api/jobs/:id/runs/:runIdRun detail: per-candidate scores + evidence spans
GET/api/jobs/:id/candidatesCandidate list (metadata only — no resume text)
GET/api/jobs/:id/candidates/:cidCandidate detail: parsed profile, document text, decisions
GET/api/jobs/:id/reviewRanked review table: latest overall per candidate + stage
POST/api/jobs/:id/decisionsRecord a decision (stage + required reason; audit-chained)
PATCH/api/jobs/:id/scores/:scoreIdManual score override (author + reason recorded)
PUT/api/jobs/:id/demographics/:cidCandidate's opt-in demographics self-report
POST/api/jobs/:id/bias-auditAdverse-impact report (four-fifths rule; audited)
GET/api/openapi.jsonThe 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.