API reference · v1 · GA

cvparser.io API

Drop in a CV in any format — get back clean structured JSON in <2 seconds. REST, JSON-only, bearer-token auth. Choose your AI provider (Claude, GPT-4, or local spaCy NER) at the workspace level.

Base URL: https://api.cvparser.io
Latest version: v1.0.0
Schema: Candidate v1 — 71 fields

Overview

cvparser converts CVs into a normalised candidate object validated by Zod. Upload PDF, DOCX, DOC or HTML to /v1/parse, or send plain text to /v1/parse/text. Every parse runs through the same extractor pipeline.

  • One synchronous endpoint. Most CVs respond inline in 1–2s.
  • Strict schema. Missing fields are null — we never hallucinate values.
  • Public demo. Try the API without auth via /demo/parse.

Authentication

All non-demo requests must include an Authorization header with a workspace bearer token. Tokens are managed in your Dashboard. Every key is prefixed cvp_.

Keep keys server-side
Don't ship live keys in browser bundles or mobile apps. Use a thin proxy on your backend. Rotate keys quarterly from the dashboard — old keys remain valid for 30 days.

Quickstart

Send your first parse with a single command. The response wraps the candidate object in { success, data }. Costs 1 credit on a 2xx response. To only extract the sections you need (and cut LLM cost), see Selecting sections below.

POST/v1/parse
curl -X POST https://api.cvparser.io/v1/parse \
  -H "Authorization: Bearer cvp_a8f...kT2" \
  -F "file=@./candidate.pdf"
Response
{
  "success": true,
  "data": {
    "fullName": "Sarah Chen",
    "headline": "Senior Frontend Engineer",
    "email": "sarah.chen@gmail.com",
    "phone": "+44 7700 900123",
    "location": "London, UK",
    "linkedin": "https://linkedin.com/in/sarahchen",
    "github": null,
    "website": null,
    "bio": "Frontend engineer with 8+ years...",
    "confidence": 0.994,
    "workHistory": { "confidence": 0.97, "items": [ ... ] },
    "education":   { "confidence": 0.99, "items": [ ... ] },
    "skills":      { "confidence": 0.96, "items": [ ... ] }
  }
}

Selecting sections

By default a parse returns every CV section. Pass `?sections=` (on /parse) or a JSON `sections: []` field (on /parse/text) to extract only what you need — the request builds a reduced JSON schema, trims the prompt, and costs proportionally less. The response still uses the same envelope; unrequested sections are simply omitted from `data`.

POST/v1/parse?sections=…
Valid section keys
candidate · workHistory · education · skills · certifications · licences · projects · courses · languages · publications · patents · honorsAwards
  • Comma-separated on the REST query (?sections=workHistory,skills); a JSON array on /parse/text.
  • Omitted⇒ full extraction (every section). Pass nothing to keep today's behaviour.
  • Unknown keys 400. Validation happens before any LLM call, so you never pay for a typo.
  • Field-level narrowing within a list section (e.g. only the company + title of each work-history item) is GraphQL-only — POST your query to /v1/parse/graphql, using the same bearer token.
curl -X POST "https://api.cvparser.io/v1/parse?sections=workHistory,skills" \
  -H "Authorization: Bearer cvp_a8f...kT2" \
  -F "file=@./candidate.pdf"
Response
{
  "success": true,
  "data": {
    "workHistory": { "confidence": 0.97, "items": [ ... ] },
    "skills":      { "confidence": 0.96, "items": [ ... ] }
  }
}

Errors

cvparser uses conventional HTTP status codes. 2xx for success, 4xx for client errors (validation, auth, quota), 5xx for our problems. Errors always include a JSON envelope { success: false, error: string }.

200OKParse succeeded.
400invalid_fileFile missing, unreadable, or unsupported MIME.
406not_multipartBody was not multipart/form-data. /v1/parse takes a file upload.
401invalid_api_keyMissing / malformed / revoked bearer token.
402insufficient_creditsWorkspace is out of credits.
413file_too_largeAbove the 25 MB per-file cap.
422low_confidenceParsed, but overall confidence below the workspace threshold.
429rate_limitedSlow down — see Retry-After header.
500internal_errorOur side. Auto-retried 3× before surfacing.

Rate limits

60 requests / minute per workspace by default — get in touch to raise it. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a rejected request returns 429 with Retry-After. The public demo endpoint is limited separately to 5 requests / hour per IP.

The Candidate object

Every parse returns a Candidate envelope, validated server-side against a single Zod contract. The top-level keys are below; every section item shape is listed under them, so nothing about the response needs guessing.

Param
Type
Notes
fullNamerequired
string
Candidate's full name.
headlinerequired
string
Brief professional focus line.
emailrequired
string
Best-known email address.
phonerequired
string
Phone number, format preserved.
locationrequired
string
City / region / country.
biorequired
string
Top-of-CV personal statement.
linkedin
string | null
LinkedIn profile URL, or null.
github
string | null
GitHub profile URL, or null.
website
string | null
Personal site URL, or null.
workHistoryrequired
object
{ confidence, items[] } — roles with title, company, dates, description, skills.
educationrequired
object
{ confidence, items[] } — institution, degree, field, dates.
skillsrequired
object
{ confidence, items[] } — { name, type: 'soft' | 'tech' }.
certificationsrequired
object
{ confidence, items[] }.
languagesrequired
object
{ confidence, items[] } — language + proficiency: elementary | limited | professional | full | native.
projectsrequired
object
{ confidence, items[] }.
publicationsrequired
object
{ confidence, items[] }.
patentsrequired
object
{ confidence, items[] }.
honorsAwardsrequired
object
{ confidence, items[] }.
coursesrequired
object
{ confidence, items[] }.
licencesrequired
object
{ confidence, items[] }.
confidencerequired
number
Overall extraction confidence 0–1.
Item shapes
// Dates are day-first strings: "31/12/2016" | "12/2016" | "2016".
// A current role/course omits endDate and sets current: true.

workHistory.items[]   { type: "employment" | "volunteer"
                        title: string
                        company: string
                        startDate: string
                        endDate: string | null
                        current: boolean
                        description: string
                        skills: { name: string, type: "soft" | "tech" }[] }

education.items[]     { institution: string
                        degree: string
                        field: string
                        startDate: string
                        endDate: string | null
                        current: boolean }

skills.items[]        { name: string, type: "soft" | "tech" }

certifications[]      { name: string
                        issuingOrganization: string
                        credentialId: string
                        credentialUrl: string | null
                        issuedAt: string | null
                        expiresAt: string | null
                        doesNotExpire: boolean }

licences.items[]      { name: string
                        issuingAuthority: string
                        licenceNumber: string
                        issuedAt: string | null
                        expiresAt: string | null
                        doesNotExpire: boolean }

projects.items[]      { name: string
                        description: string
                        url: string | null
                        startDate: string | null
                        endDate: string | null
                        current: boolean
                        skills: { name: string, type: "soft" | "tech" }[] }

courses.items[]       { name: string
                        provider: string
                        completedAt: string | null
                        credentialUrl: string | null }

languages.items[]     { language: string
                        proficiency: "elementary" | "limited" | "professional"
                                   | "full" | "native" }

publications.items[]  { title: string
                        publisher: string
                        authors: string[]
                        publishedAt: string | null
                        url: string | null
                        description: string }

patents.items[]       { title: string
                        patentNumber: string | null
                        status: "pending" | "granted" | "expired"
                        inventors: string[]
                        issuingOffice: string
                        issuedAt: string | null
                        filedAt: string | null
                        url: string | null
                        description: string }

honorsAwards.items[]  { title: string
                        issuer: string
                        issuedAt: string | null
                        description: string }

Parse a CV (file upload)

Multipart upload. PDF, DOCX, DOC and HTML are supported; any other file type is rejected with 400. For plain text, post to /v1/parse/text with a JSON body instead. Costs 1 credit per parse — charged only on a 2xx response.

POST/v1/parse
Param
Type
Notes
filerequired
binary
Multipart file field. ≤ 25 MB.
sections
query (csv)
Optional. Comma-separated list of section keys to extract — see Selecting sections.
curl -X POST https://api.cvparser.io/v1/parse \
  -H "Authorization: Bearer cvp_a8f...kT2" \
  -F "file=@./candidate.pdf"
Response
{
  "success": true,
  "data": {
    "fullName": "Sarah Chen",
    "headline": "Senior Frontend Engineer",
    "email": "sarah.chen@gmail.com",
    "phone": "+44 7700 900123",
    "location": "London, UK",
    "linkedin": "https://linkedin.com/in/sarahchen",
    "github": null,
    "website": null,
    "bio": "Frontend engineer with 8+ years...",
    "confidence": 0.994,
    "workHistory": { "confidence": 0.97, "items": [ ... ] },
    "education":   { "confidence": 0.99, "items": [ ... ] },
    "skills":      { "confidence": 0.96, "items": [ ... ] }
  }
}

Parse a CV (raw text)

Send pre-extracted CV text directly — skips file extraction. Useful when you already have the text from another source.

POST/v1/parse/text
Param
Type
Notes
textrequired
string
Raw CV text. Minimum 30 characters.
sections
string[]
Optional JSON array of section keys to extract — see Selecting sections.
curl -X POST https://api.cvparser.io/v1/parse/text \
  -H "Authorization: Bearer cvp_a8f...kT2" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Sarah Chen\nSenior Frontend Engineer..." }'
Response
{
  "success": true,
  "data": {
    "fullName": "Sarah Chen",
    ...
  }
}

Public demo endpoint

Unauthenticated, IP-rate-limited demo endpoint. Same response shape as /parse. Use it to wire up trial flows or evaluation harnesses without provisioning a key.

POST/demo/parse
Not for production
The demo endpoint is rate-limited per IP and may have looser SLAs. Move to the authenticated endpoint as soon as you have a key.
curl -X POST https://api.cvparser.io/demo/parse \
  -F "file=@./candidate.pdf"
Response
{
  "success": true,
  "data": { ... }
}

Libraries & SDKs

The API is plain REST — any HTTP client works. Below are the no-dependency choices for the popular languages.

Node.js
Node 18+
global fetch + FormData (built-in)
Python
3.8+
pip install requests
Go
stdlib
net/http + mime/multipart
REST
v1.0.0
curl, fetch, axios — anything