Resumes & Parsing API
The end-to-end lifecycle for ingesting unstructured candidate resumes (PDF, DOCX, images), extracting normalized JSON schemas with high-accuracy AI models, running automated proofreading, re-rendering branded Word documents, and managing data retention.
How the asynchronous resume pipeline works
Resume parsing in CVFormatter is asynchronous to ensure consistent throughput, even when processing complex multi-page PDF documents or high-resolution scanned graphics. The parsing lifecycle follows these distinct phases:
Multipart binary is validated, assigned an ID, and SHA-256 hashed. Replays within 24h are deduplicated automatically with 0 credit deduction.
OCR and multi-modal models extract candidate contact details, work history, skills, certifications, and educational milestones.
If auto_proofread=true is passed, an automated linguistic pass cleans typos, tense inconsistencies, and formatting flaws.
Retrieve structured JSON directly or compile candidate profiles into standardized corporate Word (.docx) templates or 30-day preview URLs.
Recommended Polling & Retry Strategy
Upon submitting a file to POST /resumes, your client receives an HTTP 202 Accepted with status PENDING. Poll GET /resumes/:id every 2.0 to 3.5 seconds. Average processing time is 4โ8 seconds. Once status transitions to COMPLETED, retrieve structured data via GET /resumes/:id/data.
/resumes
Upload and ingest resume
Initiates asynchronous parsing for PDF, DOCX, DOC, PNG, or JPEG files up to 20MB. Deduplication logic checks existing files; replaying identical file bytes returns deduplicated=true with zero credits consumed.
Parameters
| Field | Type & Description | Required |
|---|---|---|
| file | Binary fileResume document binary (PDF, DOCX, DOC, PNG, JPEG up to 20MB). | Yes |
| auto_proofread | text / booleanSet to "true" to automatically queue AI proofreading once initial parsing finishes. Consumes 1 proofread credit. | No |
| title | stringDisplay name for the resume. Defaults to the uploaded file name if omitted. | No |
| template_id | stringDefault corporate export template ID to bind to this candidate profile. | No |
| recruiter_id | stringOptional when using Organization Keys to assign ownership to a specific team member. | No |
| Idempotency-Key | Header (string)8โ128 character client-generated UUID preventing duplicate credit charges on connection drops. | Yes |
curl --fail-with-body -X POST "$CVF_BASE_URL/resumes" \
-H "Authorization: Bearer $CVF_API_KEY" \
-H "Idempotency-Key: candidate-123-upload-v1" \
-F "file=@./resume.pdf" \
-F "auto_proofread=true" \
-F "title=Candidate Resume.pdf" \
-F "template_id=TEMPLATE_ID" \
-F "recruiter_id=RECRUITER_ID"{
"id": "CV_EXAMPLE",
"status": "PENDING",
"deduplicated": false,
"credits_reserved": 1,
"recruiter_id": "RECRUITER_ID",
"status_url": "/api/v1/public/resumes/CV_EXAMPLE",
"data_url": "/api/v1/public/resumes/CV_EXAMPLE/data",
"request_id": "REQUEST_ID"
}/resumes/:id
Poll parsing status & lifecycle timestamps
Poll this endpoint to monitor processing progression. Status transitions through PENDING -> PROCESSING -> COMPLETED (or FAILED with diagnostic error details).
curl --fail-with-body -X GET "$CVF_BASE_URL/resumes/CV_EXAMPLE" \
-H "Authorization: Bearer $CVF_API_KEY"{
"id": "CV_EXAMPLE",
"recruiter_id": "RECRUITER_ID",
"uploaded_via_api_key": {
"id": "KEY_RECORD_ID",
"name": "ATS integration"
},
"title": "Candidate Resume.pdf",
"status": "COMPLETED",
"source": "FILE_UPLOAD",
"created_at": "2026-10-10T04:00:00.000Z",
"updated_at": "2026-10-10T04:00:00.000Z",
"expires_at": "2026-11-09T04:00:00.000Z",
"processing_started_at": "2026-10-10T04:00:00.000Z",
"processing_finished_at": "2026-10-10T04:00:00.000Z",
"resume_language": "english",
"error": null
}/resumes/:id/data
Retrieve parsed structured JSON
Returns standardized JSON containing candidate personal information, work history, skill taxonomy, and qualifications. Requires the parsing job to be in COMPLETED status (returns HTTP 409 RESUME_NOT_READY if currently processing).
curl --fail-with-body -X GET "$CVF_BASE_URL/resumes/CV_EXAMPLE/data" \
-H "Authorization: Bearer $CVF_API_KEY"{
"id": "CV_EXAMPLE",
"data": {
"basic_info": {
"first_name": "Alex",
"last_name": "Morgan",
"full_name": "Alex Morgan",
"email": "alex@example.com",
"phone_number": "+1 555 0100",
"current_org": "Example Ltd",
"current_title": "Engineer",
"location": {
"city": "London",
"country": "UK"
},
"summary_description": [
"Senior Software Engineer with 8+ years leading cloud backend integrations."
]
},
"education": [
{
"degree": "B.Sc. Computer Science",
"institution": "University of London",
"start_date": "2015",
"end_date": "2018"
}
],
"work_history": [
{
"role_title": "Staff Backend Engineer",
"company": "Example Ltd",
"location": "London, UK",
"start_date": "2021-03",
"end_date": "Present",
"bullet_points": [
"Architected high-throughput ingestion pipelines handling 100k requests/minute.",
"Mentored 6 junior engineers and migrated legacy microservices to Next.js and Go."
]
}
],
"skills": [
"TypeScript",
"Python",
"SQL",
"Docker",
"AWS",
"Kubernetes"
],
"resume_language": "english"
}
}/resumes?limit=20
List organization resumes (Cursor paginated)
Fetches an array of candidate records with opaque cursor pagination. Default limit is 20 records (supports values from 1 to 100). Expired documents are automatically filtered out.
curl --fail-with-body -X GET "$CVF_BASE_URL/resumes?limit=20" \
-H "Authorization: Bearer $CVF_API_KEY"{
"data": [
{
"id": "CV_EXAMPLE",
"recruiter_id": "RECRUITER_ID",
"title": "Candidate Resume.pdf",
"status": "COMPLETED",
"created_at": "2026-10-10T04:00:00.000Z"
}
],
"next_cursor": "cursor_eyJpZCI6IkNWX0VYQU1QTEUifQ"
}/resumes/:id
Update resume metadata & title
Renames the display title of the resume record (1โ255 characters). Does not alter parsed candidate entities or re-run parser models.
Request Body (JSON)
{
"title": "Updated Candidate Name - Senior Dev.pdf"
}curl --fail-with-body -X PATCH "$CVF_BASE_URL/resumes/CV_EXAMPLE" \
-H "Authorization: Bearer $CVF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Updated Candidate Name - Senior Dev.pdf"}'{
"id": "CV_EXAMPLE",
"title": "Updated Candidate Name - Senior Dev.pdf",
"request_id": "REQUEST_ID"
}/resumes/:id/reprocess
Reprocess original file binary
Re-runs AI document extraction and normalization on the original file. Consumes 1 resume credit. Pass auto_proofread: true to simultaneously trigger an automated proofreading pass.
Note: Requires an Idempotency-Key header. Reprocessing is blocked if an existing proofreading pass is actively in progress.
Request Body (JSON)
{
"auto_proofread": true
}curl --fail-with-body -X POST "$CVF_BASE_URL/resumes/CV_EXAMPLE/reprocess" \
-H "Authorization: Bearer $CVF_API_KEY" \
-H "Idempotency-Key: candidate-123-reprocess-v1" \
-H "Content-Type: application/json" \
-d '{"auto_proofread": true}'{
"id": "CV_EXAMPLE",
"replayed": false,
"credits_reserved": 1,
"status_url": "/api/v1/public/resumes/CV_EXAMPLE",
"data_url": "/api/v1/public/resumes/CV_EXAMPLE/data"
}/resumes/:id/export
Export to formatted Word DOCX binary
Renders the normalized resume into a branded Microsoft Word (.docx) file binary stream. If template_id is omitted, the engine automatically resolves your fallback hierarchy: explicit request -> resume template -> recruiter preference -> organization default.
Note: Sending an empty JSON payload {} is fully valid and invokes the automatic template fallback chain.
Parameters
| Field | Type & Description | Required |
|---|---|---|
| template_id | stringSpecific branded DOCX template ID. Omit to use the fallback chain. | No |
| format | "docx"Target export document format (defaults to "docx"). | No |
Request Body (JSON)
{
"template_id": "TEMPLATE_ID",
"format": "docx"
}curl --fail-with-body -X POST "$CVF_BASE_URL/resumes/CV_EXAMPLE/export" \
-H "Authorization: Bearer $CVF_API_KEY" \
-H "Content-Type: application/json" \
-d '{}' \
-o "resume.docx"Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Content-Disposition: attachment; filename="Candidate.docx"
X-Request-Id: REQUEST_ID[Binary Document Bytes: Word DOCX Document]/resumes/:id/preview
Generate 30-day Office Online preview link
Generates a signed, temporary file download URL alongside an authenticated Microsoft Office Online embed preview link that remains valid for 30 days. Perfect for displaying embedded resume viewers within web portals and applicant tracking apps.
Request Body (JSON)
{
"template_id": "TEMPLATE_ID"
}curl --fail-with-body -X POST "$CVF_BASE_URL/resumes/CV_EXAMPLE/preview" \
-H "Authorization: Bearer $CVF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"template_id":"TEMPLATE_ID"}'{
"file_url": "https://storage.cvformatter.co/signed/CV_EXAMPLE.docx?token=...",
"preview_url": "https://view.officeapps.live.com/op/embed.aspx?src=https%3A%2F%2Fstorage.cvformatter.co%2Fsigned%2FCV_EXAMPLE.docx",
"expires_at": "2026-11-09T13:15:00.000Z",
"filename": "Candidate.docx"
}/resumes/:id
Delete resume & queue data cleanup
Permanently deletes the resume metadata record from the primary database and queues encrypted storage blobs for asynchronous garbage collection in compliance with GDPR and CCPA privacy standards.
Note: Deletion does not refund consumed parsing or proofreading credits.
curl --fail-with-body -X DELETE "$CVF_BASE_URL/resumes/CV_EXAMPLE" \
-H "Authorization: Bearer $CVF_API_KEY"{
"id": "CV_EXAMPLE",
"deleted": true,
"cleanup_status": "queued"
}