-
Notifications
You must be signed in to change notification settings - Fork 0
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.
| 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.
| 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) |
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.
| 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 |
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.