Skip to content

API Reference

_david edited this page Sep 26, 2026 · 2 revisions

API Reference

All /api/v1/* routes require a JWT (Authorization: Bearer <token> or an httpOnly auth cookie) except /auth/*. A cookie-only, state-changing request must also carry a valid double-submit CSRF token — see Authentication. Interactive docs: GET /api-docs (Swagger UI), raw spec at GET /api-docs.json.

Auth — /api/v1/auth (rate limit: 150 req/15min)

Method Path Description
POST /register Create account. Body: { email, password, repassword }
POST / GET /login Returns access + refresh tokens (also sets httpOnly cookies). GET deprecated
POST /logout Blacklist the current access token (CSRF-checked)
POST /logout-all Revoke every token issued to this candidate up to now
POST /refresh Rotate tokens; blacklists the old refresh token (CSRF-checked)
POST /forgot-password Request a password reset — stub, logged not emailed
POST /reset-password Reset password using a reset token from /forgot-password
GET /verify-email Verify email using a token issued on register — stub, logged not emailed

All responses honor Accept-Language: en (default: Vietnamese) — see Authentication.

POST /api/v2/auth/register and /login exist and now call the exact same controller as v1 (no longer a separate buggy implementation — see Architecture), just without the rest of v1's auth endpoints.

Candidate — /api/v1/candidate

Method Path Description
GET /:email Get profile by email (password field is stripped)
PUT /update Full update — self only (req.user._id, ignores any _id in the body)
PATCH /update Partial update — same self-only rule
DELETE / Delete own account and cascade-delete (hard delete, not soft) all CV section + application + profile documents. Self only, no confirmation step
POST /upload-cv Upload a PDF résumé (multer, max 5MB)
GET /cv-file Download own previously uploaded résumé
POST /parse-linkedin-export Parse a LinkedIn "Data export" ZIP (Education.csv/Positions.csv) into Education/Experience shapes — stateless, nothing is persisted, the frontend maps the result into its own create forms for review
GET /visits Own public-profile visit count + list (recorded via POST /api/me/:email/visit)

CV Sections + Application + Profile — all follow the same shape

Sections: education, experience, award, certificate, project, reference, generalInformation (mounted as general-information in the URL), application, profile.

Method Path Description
GET / List all entries for the authenticated candidate (optional ?page=&limit=&sort=)
POST /create Create entry
PUT /update Update entry — ownership checked against the existing document's candidateId, soft-deleted documents excluded
DELETE /delete/:id Soft-delete by ID (sets deletedAt) — ownership checked
POST /restore/:id Restore a soft-deleted entry by ID

generalInformation additionally has PATCH /update for partial updates, but no delete/restore route (single document per candidate). profile's GET / synthesizes a default "Tổng hợp" (All) profile on first read if the candidate has none yet.

Free-text fields (description on education/experience/award/certificate/project, generalInformation.career/careerGoal, Candidate.introduction) are { vi: string, en: string } objects on create/update — see Data Models.

Public / misc

Method Path Auth Description
GET /health none Health check, exempt from rate limiting
GET /api/me/:email none Aggregated public profile (candidate + generalInformation + all CV sections). :email also accepts a candidate's vanity slug, checked first. Accepts ?lang=vi|en (resolves localized fields to a single string, default vi, falls back to whichever language has content) and ?profile=<id> (filters sections to that CV profile — see Architecture). Returns not-found if the candidate has set isPublic: false.
POST /api/me/:email/visit none Records a visit (count, timestamp, IP, geo via geoip-lite) against the target candidate
GET /api/v1/download-pdf token via ?token= query param Export own CV. ?format=pdf|json|docx (default pdf) — json returns the same aggregated data used to render the PDF, docx returns an editable Word document. Also accepts ?lang=vi|en.
GET /api-docs none Swagger UI
GET /api-docs.json none Raw OpenAPI spec

Example: register → login → create an education entry

curl -X POST https://nodejs-resume-api-ts.onrender.com/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"me@example.com","password":"MyPass123!","repassword":"MyPass123!"}'

TOKEN=$(curl -s -X POST https://nodejs-resume-api-ts.onrender.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"me@example.com","password":"MyPass123!"}' | jq -r .data.token)

curl -X POST https://nodejs-resume-api-ts.onrender.com/api/v1/education/create \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"_id":null,"school":"My University","major":"Computer Science","startDate":1600000000000,"endDate":1700000000000,"isCurrent":false,"description":{"vi":"Mô tả","en":"Description"}}'

This example authenticates with the Authorization: Bearer header, which never needs a CSRF token (CSRF only guards requests authenticating purely off the auth cookie) — see Authentication.

Clone this wiki locally