ResumeJSON

Lever resume parsing API: what it parses, and when you need more

Lever resume parsing API: what you get back, and where it stops

The Lever resume parsing API is the parse=true option on Lever's Create an Opportunity endpoint. Upload a resume file with that flag set and Lever fills in the contact's name, headline, emails, phones, location, company and links. The fuller result, a list of positions and schools, is exposed separately as parsedData on the opportunity's resume records. If you are building an internal workflow on a Lever account you already pay for, that is often all you need. If you need skills, languages, certifications, or a parse of a CV that never goes into Lever, you need a parser of your own.

This article is for the developer writing that integration. Everything about Lever below was read from Lever's public developer documentation at hire.lever.co/developer/documentation, as of September 2026. We build ResumeJSON, a resume parsing API, so read the last sections as written by an interested party.


How resume parsing works in the Lever API

There are two moments where parsing shows up in the Lever API: when you create a candidate, and when you read one back.

Creating an opportunity with parse=true

POST /opportunities accepts a resume file alongside the usual candidate fields. Lever's documentation describes the flag this way:

If set to true and a resume file is provided, the resume will be parsed and extracted data will be used to autofill information about the contact such as email and phone number. Any fields manually passed to the endpoint take precedence over any parsed data.

The fields it can fill are listed a few lines further down: name, headline, emails, phones, location, company and links. Lever adds that "no information is guaranteed to be extracted", which is an honest description of any parser. The headline is worth knowing about: Lever says it is "typically a list of previous companies where the contact has worked or schools that the contact has attended", so it is a summary string rather than a job title.

Two practical rules follow from the documentation:

Reading parsedData back from resumes

GET /opportunities/:opportunity/resumes lists the resume files on an opportunity. Each one carries a file object with a processing status (one of processing, processed, unsupported, error or null) and a parsedData object. That object holds two arrays:

ArrayWhat Lever says it contains
positionsCompany name, location, job title, job summary, start and end date
schoolsSchool name, degree, field of study, school summary, start and end date

In Lever's own example, a position looks like org, title, summary, location, plus start and end as { "year": 2016, "month": 3 } objects. The documentation also says this data "can be parsed from the candidate's resume, LinkedIn profile, or entered manually", so a record in parsedData did not necessarily come from the PDF.

Check status before you read parsedData. A resume still at processing has nothing to read yet, and one at unsupported or error never will.

Access and limits

The Lever API is for Lever customers. You authenticate with basic auth, using an API key created under Settings, "Integrations and API", on the "API Credentials" tab. Partner apps that serve many Lever accounts use OAuth and have to be registered. The default rate limit is a steady 10 requests a second per API key, with bursts up to 20. There is no standalone "parse this file" endpoint: parsing happens as a side effect of creating a candidate in a Lever account.

What the Lever parse leaves out

Set the two halves side by side and the gaps are clear. Lever's parse is built to autofill a candidate profile, and it does that. It is not built to hand you a complete, typed record of the CV.

Question your code asksLever parse=true and parsedData
Name, email, phone, linksYes, on the opportunity
Job history with datesYes, in positions
EducationYes, in schools
A list of skillsNot in the documented fields
Spoken languagesNot in the documented fields
Certifications and licencesNot in the documented fields
Total years of experienceNot in the documented fields; compute it from positions
Parse a CV without creating a candidateNo
Use outside a Lever accountNo

None of those gaps matter if a recruiter reads the profile in Lever. They matter the moment code has to decide something: filtering on a skill, checking for a licence, or matching candidates to roles.

When the Lever parse is enough

Stay with Lever's own parsing when all of these hold:

That is a common case for an internal integration. Lever already stores the file, parses it, and shows the result in the profile. Adding another parser to repeat work Lever already does costs money and gains nothing.

When you need a separate parser

There are four situations where the Lever parse does not reach, and they are the ones developers most often run into.

You are building the job board, not the ATS

A careers site or job board that wants to autofill its application form has to parse the CV before anything exists in Lever. Creating an opportunity only to read the parse back would put every half-finished application into the hiring pipeline. A standalone parse runs on the file alone and lets the applicant correct the fields before they submit.

Your rules need skills, languages or certifications

Automated resume screening and matching read fields that parsedData does not document. You can pull the positions and run your own skill extraction over each summary, as described in extract skills from resume, but at that point you are maintaining a parser anyway.

Your product serves more than one ATS

If you sell to recruiters on Lever, Greenhouse and others, each ATS parses differently and exposes the result in a different shape. Parsing once, in one schema, gives your code one record to read whatever system the candidate ends up in.

You have a backlog outside Lever

A folder of old CVs, an export from a previous system, or files from a sourcing tool: none of them are opportunities yet. Bulk resume parsing covers running a backlog through a parser once and storing the results.

How to use a parsing API alongside Lever

The two work well together. The pattern is: parse first, then create the opportunity with the fields you already have.

  1. Parse the file with the API of your choice and keep the full JSON in your own store.
  2. Create the opportunity in Lever with name, emails, phones and links taken from the parse, and attach the original file. Because manually passed fields take precedence, you can still set parse=true and let Lever fill anything you left empty.
  3. Put the rest where your code reads it. Skills, languages and certifications live in your own database, or as tags on the opportunity if recruiters should see them.
  4. Key your record on the Lever opportunity id so you can join the two later.

Step 1 with ResumeJSON is one request. The file goes up as multipart form data:

import { readFile } from 'node:fs/promises'

const form = new FormData()
form.set('file', new Blob([await readFile('cv.pdf')]), 'cv.pdf')

const res = await fetch('https://resumejson-resume-cv-parser-api.p.rapidapi.com/v1/parse', {
  method: 'POST',
  headers: {
    'x-rapidapi-key': process.env.RAPIDAPI_KEY,
    'x-rapidapi-host': 'resumejson-resume-cv-parser-api.p.rapidapi.com'
  },
  body: form
})

const { resume } = await res.json()
// resume.basics.full_name, resume.basics.email, resume.basics.phone, resume.basics.links
// resume.work[], resume.education[], resume.skills[], resume.certifications[], resume.languages[]

Lever parse and ResumeJSON, field by field

FieldLeverResumeJSON
Contact detailsname, emails, phones, links, locationbasics.full_name, email, phone, links, location
HeadlineSummary of past companies or schoolsbasics.headline, the title line when the CV states one
Work historypositions[] with org, title, summary, dateswork[] with company, title, highlights[], is_current, dates
Educationschools[]education[] with institution, degree, field_of_study
SkillsNot documentedskills[]
LanguagesNot documentedlanguages[] with proficiency
CertificationsNot documentedcertifications[] with issuer and date
Experience totalCompute it yourselftotal_years_experience
Dates{ year, month } objectsYYYY-MM or YYYY strings, null when absent
Needs a Lever accountYesNo

ResumeJSON reads PDF, DOCX, plain text and images of a page, and returns null for a value the CV does not state rather than guessing one. As of September 2026 it is sold through RapidAPI, with a free Basic plan of 100 parses a month; the docs carry the current plans and the full field reference. You can try a real CV in the free parser before writing any code.

Summary

If you are designing the storage around this, how to build an ATS covers the data model, and JSON Resume schema covers a common interchange format for the parsed record.

All articles