API Reference
Everything you need to integrate Resume Parser into your application. Sign up with your email, create an API key in the dashboard, and send your first PDF.
Overview
One endpoint: send a PDF, get structured JSON back in the same response.
Base URL: https://api.resumeparser.cc
Authentication: send your key as Authorization: Bearer rp_live_.... Keys are created in the dashboard after you sign up with your email. Keep the key on your server, never in browser code.
Limits: PDF only, up to 5 MB. 30 requests per minute per key, and at most 2 parses running at once per key. Requests rejected before parsing (for example 402, 413 or 429) do not count toward the rate limit. Parsing is synchronous and can take up to 60 seconds, so set your HTTP client timeout to at least 60 seconds.
No OCR: scanned PDFs without a text layer return 422.
Billing: 50 free parses per month, then prepaid credits bought by card in the dashboard (1 credit = 1 successful parse): EUR 0.15 per parse for 100 to 1,999 credits, EUR 0.12 for 2,000 to 9,999, EUR 0.10 for 10,000 or more, excluding VAT. Credits never expire and failed parses are not charged.
/v1/parseParse a resume PDF and receive structured JSON.
Bearer rp_live_...multipart/form-datafile (PDF)5 MBcurl https://api.resumeparser.cc/v1/parse \
-H 'Authorization: Bearer rp_live_...' \
-F '[email protected];type=application/pdf'import { readFile } from "node:fs/promises";
const pdf = await readFile("resume.pdf");
const formData = new FormData();
formData.append("file", new Blob([pdf], { type: "application/pdf" }), "resume.pdf");
const response = await fetch("https://api.resumeparser.cc/v1/parse", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.RESUME_PARSER_API_KEY}` },
body: formData,
});
const { data, usage } = await response.json();import os
import requests
with open("resume.pdf", "rb") as pdf:
response = requests.post(
"https://api.resumeparser.cc/v1/parse",
headers={"Authorization": f"Bearer {os.environ['RESUME_PARSER_API_KEY']}"},
files={"file": ("resume.pdf", pdf, "application/pdf")},
timeout=90,
)
if response.status_code >= 500 and not response.headers.get("content-type", "").startswith("application/json"):
response.raise_for_status()
body = response.json()
if response.status_code != 200:
raise RuntimeError(body["error"]["code"])
data = body["data"]
usage = body["usage"]{
"data": { ...parsed resume, see fields below },
"usage": {
"billedAs": "free",
"freeRemaining": 49,
"creditBalance": 0
}
}Response fields
The data object. Personal details and languages are left out when they are not found, so check for missing values. workExperiences and educations are always present and can be empty.
Months and years in workExperiences are numbers. year and endYear in educations are strings (a four-digit year or an empty string; endYear can also be "Present").
{
"emailAddress": <string>,
"firstName": <string>,
"lastName": <string>,
"phoneNumber": <string>,
"locationCity": <string>,
"locationState": <string>,
"locationCountry": <string>, // locationCity, locationState and locationCountry are each returned when found; state is often missing (e.g. Finnish CVs)
"linkedInLink": <string>,
"workExperiences": [
{
"title": <string>,
"organization": <string>,
"location": <string | null>,
"skillsDescription": <string, markdown>,
"startMonth": <number>,
"startYear": <number>,
"endMonth": <number | null>,
"endYear": <number | null>,
"isOngoing": <boolean>
}
],
"educations": [
{
"degree": <string>,
"school": <string>,
"year": <string>,
"endYear": <string>,
"notes": <string>,
"location": <string | null>
}
],
"fluentLanguages": [<string>],
"languages": [
{ "language": <string>, "level": <string> }
]
}Errors
Errors use HTTP status codes and a JSON body with a machine-readable code.
{
"error": {
"code": "rate_limited",
"message": "..."
}
}| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_file | The file is missing or is not a PDF. |
| 401 | invalid_api_key | The API key is missing, wrong or revoked. |
| 402 | insufficient_credits | The free parses for this month are used and there are no credits left. |
| 413 | file_too_large | The file is larger than 5 MB. |
| 422 | parse_failed | No resume data could be extracted. The PDF needs a text layer; there is no OCR, so scanned PDFs fail here. Not charged. |
| 429 | rate_limited | More than 30 requests per minute with this key. Retry after the Retry-After header (60 seconds). |
| 429 | rate_limited | At most 2 parses can run at once per key. Retry after the Retry-After header (5 seconds). |
| 500 | server_error | Unexpected server error, or the parser could not reach its model. Retry in a minute. Not charged. |
| 503 | busy | The parser is at capacity. Retry after the Retry-After header (5 seconds). |
/v1/usageCheck this month's successful parses, free parses remaining and credit balance for the key's account. The same numbers are shown in the dashboard.
Bearer rp_live_...curl https://api.resumeparser.cc/v1/usage \
-H 'Authorization: Bearer rp_live_...'{
"usage": {
"month": "2026-10",
"successfulParses": 12,
"freeAllowance": 50,
"freeRemaining": 38,
"creditBalance": 0
}
}month is the current calendar month (UTC). successfulParses counts this month's successful parses, free and paid. The free allowance resets at the start of each month; credits never expire.
Ready to integrate?
Sign up with your email and create an API key. 50 free parses per month.