ResumeJSON

ChatGPT resume parser: build it yourself, or use an API

ChatGPT resume parser: building one yourself, and when an API is less work

Yes, you can build a ChatGPT resume parser, and for a prototype it takes an afternoon. Extract the text from the CV, send it to the OpenAI API with a JSON schema describing the fields you want, and read back an object. The model call is the easy part. The work that decides whether it holds up in production is everything around the call: getting text out of PDFs and scans, keeping dates in one format, stopping the model from filling gaps with guesses, and handling the call that fails.

This article is for the developer building a job board, an applicant tracking system or a candidate-matching tool who is weighing "just use ChatGPT" against buying a resume parser. It walks through the do-it-yourself build, the code, what the tokens cost, and the places it tends to break. Then it covers when a dedicated parsing API is less code to own.

We build ResumeJSON, a resume parser API, so read this as written by an interested party. Every statement about OpenAI's products below was read off OpenAI's own pages in September 2026, and those pages are theirs to change.


Pasting a CV into ChatGPT versus calling the API

There are two different things people mean by a ChatGPT resume parser, and only one of them is something you can ship.

Everything below is about the second one.

The ChatGPT resume parser build, step by step

A working pipeline has five parts. Only one of them is the model.

  1. Text extraction. The API takes text (and images), so a PDF or DOCX has to be turned into text first. A text-layer PDF goes through a library such as pdfplumber or pdf.js. A DOCX goes through a DOCX reader. A scan or a phone photo of a page has no text layer at all and needs OCR or an image input, which is a separate path with its own failure modes. Our OCR resume parser article covers that case.
  2. A schema. You define the object you want back: basics, a list of roles, education, skills.
  3. The call, with the schema attached so the reply is constrained to it.
  4. Normalisation. The model returns what the CV says. "Summer 2019", "06/19" and "June 2019" all have to become one sortable format if you want to order roles by date.
  5. Validation and retries. A timeout, a rate limit or a refusal has to end in a state your application can show, not an empty candidate record.

Structured Outputs is what makes the schema hold

The part that changed this build from fragile to reasonable is OpenAI's Structured Outputs feature. OpenAI's own guide describes it this way, as of September 2026:

Structured Outputs is a feature that ensures the model will always generate responses that adhere to your supplied JSON Schema, so you don't need to worry about the model omitting a required key, or hallucinating an invalid enum value.

The same guide notes that the Python and JavaScript libraries let you define the schema with pydantic.BaseModel and z.object respectively, and that safety-based refusals are programmatically detectable. So you no longer have to parse JSON out of prose or retry on a missing brace.

Read that promise carefully, though: it guarantees the SHAPE, not the values. A schema that requires start_date as a string gets a string every time. It does not stop the string being "Summer 2019", and it does not stop the model inventing a date for a role that had none, because a required field has to be filled with something.

The code

A minimal Python version, using the pattern OpenAI's guide shows:

from openai import OpenAI
from pydantic import BaseModel

class Role(BaseModel):
    company: str | None
    title: str | None
    start_date: str | None   # ask for YYYY-MM in the instructions
    end_date: str | None
    is_current: bool

class Resume(BaseModel):
    full_name: str | None
    email: str | None
    phone: str | None
    work: list[Role]
    skills: list[str]

client = OpenAI()

def parse_resume(cv_text: str) -> Resume:
    response = client.responses.parse(
        model="<the model you choose>",
        input=[
            {"role": "system", "content": (
                "Extract the resume into the schema. "
                "Dates as YYYY-MM or YYYY. "
                "If the CV does not state a value, return null. Never guess."
            )},
            {"role": "user", "content": cv_text},
        ],
        text_format=Resume,
    )
    return response.output_parsed

Three details in that snippet do most of the work:

What the snippet leaves out is the rest of the pipeline: the PDF and DOCX extraction in front of it, a date normaliser after it, and retry logic around it. Those are usually several times the size of the model call.

What a ChatGPT resume parser costs per CV

OpenAI prices the API by token. As of September 2026 its pricing page lists three GPT-6 models at standard rates:

ModelInput, per 1M tokensCached input, per 1M tokensOutput, per 1M tokens
GPT-6 Astra$10.00$1.00$50.00
GPT-6 Sol$2.00$0.20$10.00
GPT-6 Luna$0.10$0.01$0.50

The same page offers batch processing at 50% off and data residency at 10% more.

A two-page CV plus your instructions is a few thousand input tokens, and the JSON back is usually under a thousand. On the cheapest model that is a fraction of a cent per CV; on the most capable one it is a few cents. Your own token counts are what to budget from, and OpenAI's pricing page is the source for the rates.

The token bill is rarely the expensive part, though. The real cost of the build is the engineering time on extraction, normalisation and error handling, and the maintenance of that code every time a CV arrives in a shape you had not seen.

Where a do-it-yourself ChatGPT resume parser breaks

These are the problems that show up after the prototype works on your own CV.

None of these are reasons not to build it. They are the list of what you will be maintaining if you do.

When to keep ChatGPT for resume parsing

Stay with your own OpenAI build if any of these is true:

When a resume parser API is less work

A dedicated parser is the better fit when what you want is the standard resume object, reliably, from whatever file a candidate uploads, without owning the pipeline around the model.

That is the job ResumeJSON does. You send a PDF, a DOCX, plain text, or a photo or scan of the page, and get back typed JSON: contact details, every role with dates as YYYY-MM or YYYY, is_current: true on a role with no end date, education, skills, certifications and languages. A field the CV does not state comes back null rather than guessed. Median parse time is 2.2 seconds, measured against the live endpoint, and every response carries an X-Parse-Ms header so you can see it yourself.

Your own ChatGPT buildResumeJSON
File typesWhatever extraction you writePDF, DOCX, text, scan or photo
SchemaYours to design and versionFixed, documented typed resume
Date formatYours to normaliseYYYY-MM or YYYY, always
Missing valuesDepends on your schema and promptnull, never guessed
Custom fieldsAnything you can prompt forThe standard resume fields only
CostTokens plus your engineering timePer parse, from a free tier
MaintenanceYou own itWe own it

Pricing is published in full on the docs, billed through RapidAPI: a free Basic plan capped at 100 parses a month, Pro at $0 a month and $0.05 a parse, Ultra at $29 a month for 1,000 parses then $0.045 each, and Mega at $99 a month for 5,000 parses then $0.018 each.

The trade is control against code. Your own build can return anything you can describe. A parser returns one well-defined object and nothing else, and in exchange you write none of the pipeline.

How to switch from a ChatGPT parser to an API

If you already have an OpenAI build and want to try a parser alongside it, keep it cheap to compare:

  1. Pick 50 real CVs, including your worst: scans, two-column layouts, CVs in a second language.
  2. Run both on the same files and diff the fields you actually use: names, roles, dates, skills.
  3. Map the output onto your schema. If your own schema was modelled on JSON Resume, most fields line up one to one.
  4. Keep your model call for the custom part. A common end state is a parser for the standard fields and one small model call for the scoring or summary only you need.

You can try a CV without signing up on the free resume parser page, and our CV parser API comparison covers the other hosted options if you want to compare more than two.

The short answer

A ChatGPT resume parser is a good build when the output you need is custom, or when you already run an LLM pipeline and CVs are one more document type. For the standard resume object from any uploaded file, the model call is the small part, and a parser API removes the extraction, normalisation and failure handling you would otherwise own. Try both on your worst fifty CVs and let the diff decide.

All articles