PDFCraft
Extraction guide

Extract a payslip PDF to JSON

Everything below is the response the live API returned for a payslip, generated when this page was built. Not a description of what it would return — the output itself, including what it scored low on.

Who this is for

Payroll integrations, income-verification providers and lenders who need proof of earnings.

The job, in the words people search for: “extract gross, deductions and net pay from a payslip”.

What makes this shape awkward

Earnings and deductions are two tables side by side, and side-by-side tables are the case ordinal column assignment is worst at — the two can merge into one six-column table if the gutter between them is narrow.

The measured result

Pages read1
Time10 ms (10 ms/page)
Labelled fields found unprompted5
Tables2 (6 rows)
Inputpayslip.pdf (28 KB — synthetic, generated from a spec in the repo; real documents of this type cannot be published)

Fields, with a schema

Ask for the fields you want by the label printed on the page. Each answer carries the text exactly as printed (raw), the value coerced to the type you asked for, a confidence, and a bounding box you can draw on the page to check it.

curl -X POST https://api.pdfcraft.dev/v1/extract \
  -H "Authorization: Bearer $PDFCRAFT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": "<base64 of your payslip>",
    "schema": {
      "employee_number": "string",
      "pay_date": "date",
      "net_pay": "currency"
    }
  }'

What came back

Fieldrawvalueconfidence
employee_numberEMP-04412"EMP-04412"60%
pay_date2026-03-28"2026-03-28"70%
net_payGBP 3,218.403218.4 GBP70%

Every label it found without being asked

Send no schema and you get all of these, keyed by the label as printed. Useful for discovering what a new supplier’s layout actually contains before you write a schema against it.

Employee, Employee Number, Pay Period, Pay Date, Net Pay

Tables

Description · Units · Amount · 3 rows × 3 columns · page 1

Table confidence 75%. Header confidence 100% — the first row was promoted out of the data.

DescriptionUnitsAmount
Basic salary14,200.00
Overtime6.5214.50
Shift allowance4120.00

First 3 of 3 rows.

With options.rows_as_objects, the same row keyed by its header:

{
  "Description": "Basic salary",
  "Units": "1",
  "Amount": "4,200.00"
}

Description · Rate · Amount · 3 rows × 3 columns · page 1

Table confidence 75%. Header confidence 100% — the first row was promoted out of the data.

DescriptionRateAmount
Income tax20%882.90
National insurance8%353.16
Pension5%220.50

First 3 of 3 rows.

With options.rows_as_objects, the same row keyed by its header:

{
  "Description": "Income tax",
  "Rate": "20%",
  "Amount": "882.90"
}

What this does not do

Try it on your own payslip

The playground takes a file and shows the same JSON, with every bounding box drawn over the page. No key and no signup for the first few; a free key gives you 100 pages a month.

Related