Skip to content

API Reference

Sergey Emelyanov edited this page Jul 13, 2026 · 2 revisions

API Reference

The REST + SSE surface, grouped by route module (server/lib/routes/<module>.mjs). All paths default to http://127.0.0.1:4317. The code-adjacent contract lives in docs/architecture/API.md; this page is the grouped summary.

Legend: R = read-only · W = writes parent files (explicit user action) · relay = zero-token shell-out to a parent script with the fail-soft contract ({available:false, reason} HTTP 200 when the parent script is missing; structured parent "no data" is relayed as {available:true, empty:true}).

Cross-cutting envelope

  • Errors are JSON: { "error": "...", "details": [...] } with 400/404/413/429/500/502.
  • Every :name/:slug param passes sanitizePathName(); empty result → 400.
  • URL-fetching endpoints go through isValidJobUrl + safeGet (DNS-pinned).
  • LLM-calling and shell-out routes wear llmRateLimit (no-op on loopback; 10 req/min/IP on public bind).
  • Concurrent writes to applications.md / pipeline.md are serialized via withFileLock.

Routes by module

config

Method & path Purpose Mode
GET /api/config Known env keys from parent .env (secrets masked) R
POST /api/config Write KNOWN_KEYS to parent .env; empty string deletes W

health

| GET /api/health | Liveness + setup checks (version, parentVersion, checks) | R | | GET /api/dashboard | Counts, status histogram, avg score, recents | R | | GET /api/status/providers | LLM readiness {activeProvider, activeModel, keysConfigured} — no secrets | R |

activity

| GET /api/activity?limit=&type= | Last N state-changing requests from data/activity.jsonl | R |

tracker

| GET /api/tracker | Rows from data/applications.md; optional ?page=&pageSize=&status= + whole-history funnel | R | | POST /api/tracker | Add row; dedup by (company, role); status whitelist incl. Hired (v1.118.0); file-locked | W |

pipeline

| GET /api/pipeline | Pending URLs | R | | POST /api/pipeline | Add URL (isValidJobUrl-gated, dedup, file-locked) | W | | DELETE /api/pipeline?url= | Remove URL | W | | GET /api/pipeline/preview?url= | SSRF-safe JD text preview (stripped, 8 KB cap, 15 s timeout) | R |

auto-pipeline

| SSE auto-pipeline endpoint | Server-side evaluate → report → tracker chain over a JD URL; safeGet fetch, rate-limited | W |

reports / jds / content (cv, profile, portals, modes)

| GET /api/reports, GET /api/reports/:slug | List / render reports/*.md | R | | GET /api/jds, GET /api/jds/:name, POST /api/jds, DELETE /api/jds/:name | JD file CRUD (.txt, sanitized) | R/W | | GET /api/cv, PUT /api/cv | CV read / sanitized write (stripDangerousMarkdown, 1 MB cap) | R/W | | GET /api/profile | config/profile.yml parsed + raw | R | | GET /api/portals | portals.yml parsed + raw | R | | GET /api/modes, GET /api/modes/:name | Mode prompt templates | R |

runners

| POST /api/run/{doctor,verify,normalize,dedup,merge,sync-check,reconcile} | Buffered spawn of parent scripts (60 s timeout); {code, stdout, stderr} | shell-out | | GET /api/stream/{liveness,pdf} | SSE streaming runners (check-liveness.mjs, generate-pdf.mjs) | shell-out | | GET /api/output/pdfs, GET /api/output/pdfs/:name | List / download generated PDFs | R |

scan (in-process — no shell-out)

| GET /api/stream/scan?source=ats\|regional\|both | SSE scan; multi-phase done (final:false then final:true); dryRun=1, company= | W (history) | | GET /api/scan/sources | The 61-entry source registry {value,label,region,configKey?} | R | | GET /api/scan/regional/config | Effective russian_portals: config | R | | GET /api/scan-results | data/last-scan.json + workdayFallback | R |

llm (evaluate / deep / mode / apply / interview-prep)

| POST /api/evaluate | JD evaluation — live (Anthropic preferred, Gemini via gemini-eval.mjs) or {mode:'manual', prompt} | R (+jds/ on save:true) | | POST /api/evaluate/test-gemini, test-anthropic | Provider smoke tests | R | | POST /api/deep | Deep research; run:true persists to interview-prep/ | W on run | | POST /api/mode/:slug | Allowlist: batch, contacto, followup, interview-prep, patterns, project, training | R | | POST /api/apply-helper | Apply checklist (incl. knock-out pre-scan) | R | | GET/DELETE /api/interview-prep{,/:name} | Brief file management | R/W |

batch / interview / networking

| batch endpoints | Parallel batch evaluations | R | | interview turn/save/sessions | Mock-interview session flow (v1.90.0) | W (sessions) | | networking plan/save/plans | Networking planner — writes user-layer networking/net-*.md (v1.91.0) | W |

cv-studio

| POST /api/cv-studio/humanize | Voice-match rewrite | R | | POST /api/cv-studio/tailor | JD-tailored CV + cover letter behind a recruiter-checklist gate | R | | POST /api/cv-studio/add-entry | URL (isValidJobUrl + safeGet) or text → ATS bullets; suggestions only | R |

career-plan / memory / two-pager / orientation / market

| GET/PUT /api/career-plan, POST /api/career-plan/generate | User-layer config/career-plan.md + AI plan | R/W | | GET/PUT /api/memory (+ suggest) | About-me note config/memory.md, inlined into every AI request | R/W | | GET/PUT /api/two-pager, POST /api/two-pager/draft | config/two-pager.yml; {run:true} live auto-fill | R/W | | POST /api/orientation/generate | Career-orientation profile; no writes | R | | POST /api/stats/market | AI salary/market report (roles + region + currency) | R |

stats

| POST /api/stats/snapshot | Append target-role snapshot to data/role-stats.jsonl | W | | GET /api/stats/trend | Read snapshots back | R | | GET /api/stats/patterns | Parent analyze-patterns.mjs (rejection patterns, per-ATS advance rate) | relay | | GET /api/stats/lifetime | Parent stats.mjs (lifetime funnel, scanner totals, portal coverage) — v1.118.0 | relay | | GET /api/stats/salary-gap | Parent salary-gap.mjs (desired vs advertised vs actual) — v1.118.0 | relay |

followup

| GET /api/followup | Parent followup-cadence.mjs — per-application urgency | relay | | POST /api/followup/seed | Parent followup-seed.mjs --backfill — pins first follow-up dates in data/follow-ups.md | relay (W) |

usage / logos / cli-detect / openrouter / export / portals / docs-assistant / help

| GET /api/usage | Rollup of data/llm-usage.jsonl: tokens + est. USD over 24h/7d/30d/all | R | | GET /api/logo?domain= | Favicon proxy from the company's own domain (safeGet, size-capped, LRU) | R | | GET /api/cli-detect | Read-only PATH scan for installed agent CLIs; never executes them | R | | GET /api/openrouter/models | OpenRouter catalogue proxy (10-min cache, curated fallback) | R | | POST /api/export/docx | Client Markdown → .docx (dependency-free, stateless, bounded) | R | | POST /api/portals/health | Probe each tracked company's careers_url via safeGet | R | | POST /api/docs-assistant/ask | Grounded Q&A over docs/help/<lang>.md only | R | | GET /api/help/:lang | In-app help guide (falls back to en) | R |

SSE event shape

Content-Type: text/event-stream with events start, log ({stream:'stdout'|'stderr', line}), done ({code, …}), error. The consolidated scan emits one done per phase; the client (API.stream) closes only when data.final !== false.

Clone this wiki locally