API Reference
Base URL: http://localhost:3005/v1 · Production: https://careerlm-api.careerstudiomax.com/v1
Authentication
Pass your API key in the X-Api-Key header on every request.
curl -H "X-Api-Key: csk_free_v1_..." ...Key format: csk_(live|test|free)_v1_[48 hex characters]. Keys are shown once at creation — store them immediately. To rotate, use POST /developer/keys/:id/rotate.
Errors
All errors return a consistent JSON envelope:
{
"error": {
"code": "missing_cv_text",
"message": "cv_text is required",
"docs": "https://careerstudiomax.com/api/docs#cv-score"
}
}| Code | HTTP | Meaning |
|---|---|---|
| invalid_api_key | 401 | Key not found or malformed |
| daily_limit_exceeded | 429 | Over daily request limit — resets at midnight UTC |
| rate_limit_exceeded | 429 | Over per-minute RPM limit — check Retry-After header |
| tier_required | 403 | Feature needs a higher plan |
| content_policy_violation | 422 | Request blocked by career ethics guardrails |
| model_unavailable | 503 | Career AI gateway is temporarily unreachable |
| request_timeout | 504 | Model inference timed out (60s limit) |
Rate limits
| Tier | Requests/day | RPM |
|---|---|---|
| FREE | 1,000 | 10 |
| PRO | 10,000 | 60 |
| PLUS | 100,000 | 200 |
| ENTERPRISE | Unlimited | 1,000 |
Daily counters reset at 00:00 UTC. RPM limits are per-key sliding windows. The Retry-After header on 429s gives seconds until reset.
Models
| Name | Speed | Quality | Tier | Max tokens |
|---|---|---|---|---|
| careerlm-flash | Fastest | Good | FREE+ | 300 |
| careerlm-standard | Fast | Better | PRO+ | 1,500 |
| careerlm-deep | Slower | Best | PLUS+ | 4,096 |
Score a CV
Returns a structured ATS score, keyword gap analysis, section breakdown, and improvement suggestions.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| cv_text | string | required | Full CV text |
| job_description | string | optional | Target job description (improves keyword match) |
| target_country | string | optional, default GB | ISO 3166-1 alpha-2 country code |
| target_role | string | optional | Explicit target role (overrides JD inference) |
| options.include_suggestions | boolean | optional, default true | Include top_suggestions array |
const score = await client.cv.score(cvText, jobDescription, { target_country: 'NG' }) // score.ats_score → 87 // score.grade → "B+" // score.keyword_match → { matched: [...], missing: [...], coverage: 73 } // score.section_scores → { summary: 85, experience: 90, ... } // score.top_suggestions → ["Add Kubernetes", ...]
{
"ats_score": 87,
"grade": "B+",
"keyword_match": {
"matched": ["Python", "AWS", "FastAPI"],
"missing": ["Kubernetes", "Terraform"],
"coverage": 73
},
"section_scores": { "summary": 85, "experience": 90, "skills": 75, "education": 80 },
"top_suggestions": ["Add Kubernetes to skills section", ...],
"model": "careerlm-flash",
"request_id": "req_a1b2c3d4"
}Benchmark salary
PPP-adjusted salary ranges for 196 countries. Returns skill premiums, negotiation target, and equity range.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| role | string | required | Job title / career path |
| country | string | optional, default GB | ISO 3166-1 alpha-2 |
| city | string | optional | City for local adjustment |
| years_experience | integer | optional | Years of experience |
| skills | string[] | optional | Skills to compute premiums for |
| options.currency | string | optional | ISO 4217 currency code (default: local) |
{
"salary_range": { "low": 4200000, "median": 6800000, "high": 11000000 },
"currency": "NGN",
"usd_equivalent": { "median": 4500 },
"skill_premiums": [{ "skill": "dbt", "premium_percent": 12 }],
"negotiation_target": 7500000,
"negotiation_script": "Based on market data...",
"confidence": "high"
}Generate cover letter
15 professional writing modes. No banned filler phrases. Structured return includes letter, mode name, and word count.
Cover letter modes
| Mode | Name | Best for |
|---|---|---|
| 1 | Achievement-led | Strong career track records |
| 2 | Insight-led | Strategy and leadership roles |
| 3 | Problem-solution | Pain-point-heavy job specs |
| 4 | Narrative | Storytelling-friendly brands |
| 5 | Company-specific | Deep research hooks |
| 6 | Question-led | Provocative openers |
| 7 | Bold statement | High-competition roles |
| 8 | Data-driven | Metrics-heavy CVs |
| 9 | Cultural fit | Values-first organisations |
| 10 | Career transition | Changing industries/roles |
| 11 | Promotion | Internal promotions |
| 12 | Referral | When referred by someone |
| 13 | Remote | Remote-first applications |
| 14 | Multilingual | Multi-market roles |
| 15 | Executive | C-suite / Director gravitas |
Match job
Multi-dimensional match score across skills, experience, salary, location, and culture signals. Returns apply recommendation.
Skills gap
Quantified gap analysis with L1-L4 skill levels, learning hours, free resources, and salary ROI per skill acquired.
Interview questions
Role and company-specific questions with STAR model answers, follow-up probes, and common mistakes to avoid.
Career chat (OpenAI-compatible)
Drop-in OpenAI replacement. Same request/response shape. Change the base URL and model name — nothing else.
// Before: const openai = new OpenAI({ apiKey: 'sk-...' }) // After: const openai = new OpenAI({ apiKey: 'csk_free_v1_...', baseURL: 'http://localhost:3005/v1/career', defaultHeaders: { 'X-Api-Key': 'csk_free_v1_...' } })
Career context (persistent memory)
World-first: persist the candidate's profile across API calls. Save once, pass context_id to every other endpoint for automatic personalisation.
Register developer
No auth required. Returns your API key — shown once, store immediately.
{
"developer_id": "dev_abc123",
"api_key": "csk_free_v1_...", // shown once
"tier": "FREE",
"daily_limit": 1000,
"docs": "http://localhost:3006/docs"
}Usage stats
Returns today's request count, remaining daily quota, RPM limit, and recent 10 calls with masked model names.
CSTM-2 — a separate API, different base URL & auth
X-Api-Key or the api.careerstudiomax.com host. Treat it as a separate integration.CSTM-2 is CareerStudioMax's own model API, served directly by the main platform. It's organised into per-capability key families (CareerLM, CareerEmbed, CareerScore, CareerAgent, CareerVoice, CareerVision, CareerWebAPI) — this page currently only documents CareerEmbed, the semantic-embedding family. For the live, authoritative list of every CSTM-2 family and endpoint, see GET /api/cstm2/docs/models or the self-documenting reference at careerstudiomax.com/developer.
Base URL: https://careerstudiomax.com/api/cstm2
Authentication
Pass a CareerEmbed key (cstm_em_*, generated via the key-management UI at careerstudiomax.com/developer) as a Bearer token.
curl -H "Authorization: Bearer cstm_em_..." ...Create embeddings
384-dimensional text embeddings (Xenova/all-MiniLM-L6-v2, served by careercamp-ai).
const { CSTM2Client } = require('careerlm/cstm2') const client = new CSTM2Client('cstm_em_...') const result = await client.embed('Senior Software Engineer, distributed systems') // result.data[0].embedding → [0.0123, -0.045, ...] (384 floats)
Semantic similarity
Cosine similarity (0–1) between two texts.
| Field | Type | Required |
|---|---|---|
| text_a | string | required |
| text_b | string | required |
Semantic job matching
Ranks real, current listings from CareerStudioMax's live-harvested job feed (Adzuna, Reed, USAJOBS, Greenhouse, Lever, RemoteOK, Remotive, ArbeitNow, TheMuse, WeWorkRemotely, Jooble — never scraped or purchased data) by embedding cosine similarity to a given CV.
| Field | Type | Required | Description |
|---|---|---|---|
| cv_text | string | required | Full CV text |
| country_code | string | optional | ISO alpha-2 — falls back to a global pool if omitted or uncovered |
| limit | integer | optional, default 10 | Max 25 |
{
"matches": [
{ "title": "Senior Backend Engineer", "company": "Stripe", "matchScore": 50, "url": "...", "source": "greenhouse" }
],
"total_candidates_considered": 65,
"scoped_to_country": true,
"data_freshness": "Oldest listing considered: 9 day(s) old",
"model": "careerembed-v1"
}from careerlm.cstm2 import CSTM2Client client = CSTM2Client(api_key="cstm_em_...") result = client.match_jobs(cv_text, country_code="US", limit=10)