API Design
The kairos-api crate exposes all core functionality as a REST API, with WebSocket support for streaming LLM responses.
Server
| Framework | axum (tokio-based, tower middleware) |
| Default port | 3001 |
| Transport | HTTP/1.1 + WebSocket |
| Serialization | JSON (serde) |
Response Envelope
All endpoints return a consistent envelope:
{
"status": "success",
"data": { ... },
"message": null,
"meta": { "total": 42, "page": 1, "page_size": 20 }
}
Error responses:
{
"status": "error",
"data": null,
"message": "Job not found",
"code": "JOB_NOT_FOUND"
}
Endpoints
Jobs
| Method | Path | Description |
|---|---|---|
POST | /api/jobs/search | Start a search across platforms |
GET | /api/jobs | List jobs (paginated, filterable) |
GET | /api/jobs/:id | Get job details |
POST | /api/jobs/:id/analyze | Trigger JD analysis |
GET | /api/jobs/:id/analysis | Get analysis results |
DELETE | /api/jobs/:id | Remove a job |
Resumes
| Method | Path | Description |
|---|---|---|
POST | /api/resumes/import | Import a resume (LaTeX/Markdown) |
GET | /api/resumes | List resumes |
GET | /api/resumes/:id | Get resume details with sections |
POST | /api/resumes/:id/tailor | Tailor resume for a specific job |
GET | /api/resumes/:id/tailored | List tailored versions |
GET | /api/resumes/:id/tailored/:job_id | Get tailored version + diff |
POST | /api/resumes/:id/tailored/:job_id/approve | Approve tailored version |
POST | /api/resumes/:id/export | Export resume (PDF/LaTeX) |
Applications
| Method | Path | Description |
|---|---|---|
POST | /api/applications | Create an application record |
GET | /api/applications | List applications (paginated) |
GET | /api/applications/:id | Get application details |
PATCH | /api/applications/:id | Update status/notes |
GET | /api/applications/stats | Dashboard statistics |
Profile & Config
| Method | Path | Description |
|---|---|---|
GET | /api/profile | Get user profile |
PUT | /api/profile | Update user profile |
GET | /api/config | Get current config |
PATCH | /api/config | Update config fields |
Health
| Method | Path | Description |
|---|---|---|
GET | /api/health | Server health check |
WebSocket: LLM Streaming
Long-running LLM operations (analysis, tailoring) support WebSocket streaming:
WS /api/ws
Protocol:
// Client sends
{ "type": "analyze", "job_id": "uuid" }
// Server streams
{ "type": "progress", "stage": "extracting_requirements", "percent": 30 }
{ "type": "progress", "stage": "scoring_match", "percent": 70 }
{ "type": "complete", "data": { "score": 0.85, "analysis": { ... } } }
This allows all frontends (CLI, Web) to show real-time progress.
Authentication
For local use, the API runs on localhost with no auth required. For remote/shared deployments:
| Method | Use Case |
|---|---|
API Key (header: X-Kairos-Key) | CLI scripts, simple setups |
| JWT (Bearer token) | Web App, multi-user scenarios |
Auth is implemented as tower middleware and can be toggled in config.toml:
[api]
bind = "127.0.0.1:3001"
auth = "none" # "none", "api_key", "jwt"
api_key = "" # or set KAIROS_API_KEY env var
jwt_secret = "" # or set KAIROS_JWT_SECRET env var
Middleware Stack
Request
→ Logging (tower-http TraceLayer)
→ CORS (tower-http CorsLayer)
→ Auth (custom middleware)
→ Rate limiting (tower governor)
→ Handler
→ Response envelope wrapper
Error Mapping
API errors map domain errors to HTTP status codes:
| Domain Error | HTTP Status | Code |
|---|---|---|
NotFound | 404 | *_NOT_FOUND |
ValidationError | 400 | VALIDATION_ERROR |
LlmError | 502 | LLM_ERROR |
ScrapingError | 502 | SCRAPING_ERROR |
Unauthorized | 401 | UNAUTHORIZED |
RateLimited | 429 | RATE_LIMITED |