Skip to Content
Sending Documents

Sending Documents

Every endpoint that takes a résumé or job description accepts the same three input forms: text, url, or file. Send exactly one.

{ "text": "Jane Doe — Senior Backend Engineer\n..." } { "url": "https://example.com/resumes/jane-doe.pdf" } { "file": "JVBERi0xLjQKJcOkw7zDtsO..." }

This applies to /parse/resume, /parse/jd, /extract/*, and /redact. /match takes two documents at once, so its fields are prefixed — see below.

No matter which form you use, the document is processed transiently and deleted the moment the call ends. Nothing résumé-shaped is ever stored.

text — raw text

The simplest form, and the fastest: nothing to fetch or decode.

curl -X POST "$BASE/parse/resume" \ -H "x-access-key: $REZMATCH_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "Jane Doe\njane@example.com | +1 (415) 555-0142 | San Francisco, CA\n\nEXPERIENCE\nSenior Backend Engineer — Stripe, San Francisco, CA\nMar 2021 – Present\n- Own the payments ledger service in Go.\n\nEDUCATION\nUC Berkeley — B.S. Computer Science, 2017\n\nSKILLS\nGo, Python, PostgreSQL, Kubernetes" }'

Remember to JSON-escape newlines as \n. If what you send is actually HTML, it’s stripped to visible text before processing — you don’t have to clean up a page you scraped yourself.

url — fetch it for me

Point at a PDF or a web page and Rezmatch.ai fetches it. This is the natural form for job postings: Greenhouse, Lever, Workday, and company career pages all work directly.

curl -X POST "$BASE/parse/jd" \ -H "x-access-key: $REZMATCH_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url": "https://job-boards.greenhouse.io/acme/jobs/123456"}'

Fetch behavior:

  • http(s) only, redirects followed, 25-second timeout.
  • The fetcher identifies itself as RezMatchBot/1.0 — allowlist it if you’re pointing at a site you control that has bot mitigation.
  • HTML is reduced to its visible text before anything else happens. A job posting is overwhelmingly markup, scripts, and styles; stripping it first means your size limit is measured against the words that matter, not the page weight.
  • The URL must be reachable from the public internet. Documents behind a login, a signed S3 URL you haven’t shared, or a private network won’t work — fetch them yourself and send file instead.

A URL that times out, 404s, or refuses the connection comes back as invalid_request with the reason in the message, and costs no credits.

file — base64 bytes

Send the document itself. Use this for anything you already have in hand, or anything not publicly reachable — the common case for résumés.

curl -X POST "$BASE/parse/resume" \ -H "x-access-key: $REZMATCH_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"file\": \"$(base64 -i resume.pdf)\"}"
import base64, requests with open("resume.pdf", "rb") as f: encoded = base64.b64encode(f.read()).decode() res = requests.post( f"{BASE}/parse/resume", headers={"x-access-key": API_KEY}, json={"file": encoded}, )
import { readFile } from 'node:fs/promises'; const file = (await readFile('resume.pdf')).toString('base64'); const res = await fetch(`${BASE}/parse/resume`, { method: 'POST', headers: { 'x-access-key': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ file }), });

Base64 only — plain JSON, no multipart/form-data. A data-URI prefix (data:application/pdf;base64,) is not accepted; send just the payload.

Supported: PDF (processed natively, layout and all) and plain text. Not yet supported: DOCX, RTF, and images, which return unsupported_format. An image-only scan with no text layer returns parse_failed.

Size limits

Limits depend on your plan and on which form you used, because each form measures size differently:

FormMeasured asFreeStarterGrowthScale
file (PDF)pages2101010
textcharacters40k80k160k320k
urlcharacters of extracted text40k80k160k320k

A hard 10 MB ceiling applies to every form on every plan, before the per-plan limit is checked.

Oversized documents fail with invalid_request before any processing happens — no credits are charged. See Credits & Pricing for the full plan table.

Precedence

If you send more than one form, they’re resolved in this order and the rest are ignored:

text → file → url

Sending none of them returns invalid_request: One of text, url, or file is required.

Two documents at once: /match

/match and /score/requirements score a candidate against a role, so each side gets its own prefixed field. Both sides accept all three forms, plus a fourth option: already-parsed JSON.

SideParsed JSONTextURLFile
Candidatecandidateresume_textresume_urlresume_file
Rolerolejd_textjd_urljd_file

Mix them freely — a base64 résumé against a live job posting:

curl -X POST "$BASE/match" \ -H "x-access-key: $REZMATCH_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"resume_file\": \"$(base64 -i resume.pdf)\", \"jd_url\": \"https://job-boards.greenhouse.io/acme/jobs/123456\" }"

Each document passed inline is parsed as part of the call and adds its full parse cost — the match above costs 3 + 6 + 4 = 13 credits. Passing candidate and role JSON you parsed earlier costs just the 3. When you’re screening a pool against one role, parse once and reuse the JSON; see Credits & Pricing for the arithmetic.

Last updated on