Name fields such as invoice number, date, or policy ID, and the Data Extraction API returns each value from forms, PDFs, and scans. Every value comes with a citation to where it was found on the page, with no templates to build or maintain.
Describe the fields in a JSON Schema, and the extract endpoint returns only those values, typed as the schema asks. No templates, zones, or rules per layout.
Each value comes with a citation: its page, a bounding box, and a confidence score, so reviewers can trace it to its exact source.
The extract endpoint accepts PDFs, images, and Word, Excel, and PowerPoint files. Structure, understand, and agentic modes run OCR in more than 100 languages.
Three steps
Every extraction is a single call to the Data Extraction API extract endpoint.
Create a free account for a Data Extraction API key. The free plan includes 5,000 credits each month.
Send the document to the extract endpoint with a schema that names the fields you need, such as first name or date of birth.
The response returns the extracted values in output.data and their citations in output.metadata.
This example sends a form to the Data Extraction API extract endpoint with a JSON Schema of four fields. The response returns each value with a citation: the page, a bounding box, and a confidence score.
document.pdf. Then run the sample from the same folder. The Python and JavaScript samples save the values and citations to result.json; the shell samples save the full response.understand mode, which fits forms and printed handwriting. For cursive handwriting and degraded scans, set parseConfig.mode to agentic.curl --fail-with-body -X POST https://api.nutrient.io/extraction/extract \ -H "Authorization: Bearer your_api_key_goes_here" \ -F "file=@document.pdf" \ -F 'instructions={"schema":{"type":"object","properties":{"first_name":{"type":"string","description":"Applicant first name"},"last_name":{"type":"string","description":"Applicant last name"},"email":{"type":"string","description":"Applicant email address"},"date_of_birth":{"type":"string","description":"Applicant date of birth"}},"required":["first_name","last_name"]},"parseConfig":{"mode":"understand"}}' \ -o result.jsoncurl --fail-with-body -X POST https://api.nutrient.io/extraction/extract ^ -H "Authorization: Bearer your_api_key_goes_here" ^ -F "file=@document.pdf" ^ -F "instructions={\"schema\":{\"type\":\"object\",\"properties\":{\"first_name\":{\"type\":\"string\",\"description\":\"Applicant first name\"},\"last_name\":{\"type\":\"string\",\"description\":\"Applicant last name\"},\"email\":{\"type\":\"string\",\"description\":\"Applicant email address\"},\"date_of_birth\":{\"type\":\"string\",\"description\":\"Applicant date of birth\"}},\"required\":[\"first_name\",\"last_name\"]},\"parseConfig\":{\"mode\":\"understand\"}}" ^ -o result.json// This code requires Node.js 19.8 or later. Do not run it in a web browser.import fs from "node:fs";
const schema = { type: "object", properties: { first_name: { type: "string", description: "Applicant first name" }, last_name: { type: "string", description: "Applicant last name" }, email: { type: "string", description: "Applicant email address" }, date_of_birth: { type: "string", description: "Applicant date of birth" }, }, required: ["first_name", "last_name"],};
const form = new FormData();form.append("file", await fs.openAsBlob("document.pdf"), "document.pdf");form.append( "instructions", JSON.stringify({ schema, parseConfig: { mode: "understand" } }),);
const response = await fetch("https://api.nutrient.io/extraction/extract", { method: "POST", headers: { Authorization: "Bearer your_api_key_goes_here" }, body: form,});if (!response.ok) throw new Error(await response.text());
const result = await response.json();fs.writeFileSync("result.json", JSON.stringify(result.output, null, 2));import jsonimport requests
schema = { "type": "object", "properties": { "first_name": {"type": "string", "description": "Applicant first name"}, "last_name": {"type": "string", "description": "Applicant last name"}, "email": {"type": "string", "description": "Applicant email address"}, "date_of_birth": {"type": "string", "description": "Applicant date of birth"}, }, "required": ["first_name", "last_name"],}
with open("document.pdf", "rb") as file: response = requests.post( "https://api.nutrient.io/extraction/extract", headers={"Authorization": "Bearer your_api_key_goes_here"}, files={"file": file}, data={ "instructions": json.dumps( {"schema": schema, "parseConfig": {"mode": "understand"}} ) }, )response.raise_for_status()
result = response.json()with open("result.json", "w") as out: json.dump(result["output"], out, indent=2)Example output
An excerpt from a real response for a sample credit application with fictitious data. All four values are in output.data, and the citations for three of them are in output.metadata. See the extract endpoint guide for the full response shape.
{ "output": { "data": { "first_name": "Joanna R.", "last_name": "Simonitti", "email": "jo.simonitti89@gmail.com", "date_of_birth": "05/10/1989" }, "metadata": { "first_name": { "bbox": { "height": 22.3975830078125, "width": 114.55239868164062, "x": 284.9916076660156, "y": 1080.6031494140625 }, "citation": { "confidence": { "groundedness": 0.9921658039093018 }, "regions": [ { "bbox": { "height": 22.3975830078125, "width": 114.55239868164062, "x": 284.9916076660156, "y": 1080.6031494140625 }, "pageIndex": 0, "pageNumber": 1 } ], "status": "cited" }, "match": "id_match", "pageIndex": 0, "pageNumber": 1, "source_bboxes": [ { "bbox": { "height": 22.3975830078125, "width": 114.55239868164062, "x": 284.9916076660156, "y": 1080.6031494140625 }, "pageIndex": 0, "pageNumber": 1 } ] }, "last_name": { "bbox": { "height": 22.6395263671875, "width": 100.3316650390625, "x": 285.6653137207031, "y": 1157.3604736328125 }, "citation": { "confidence": { "groundedness": 0.9983111619949341 }, "regions": [ { "bbox": { "height": 22.6395263671875, "width": 100.3316650390625, "x": 285.6653137207031, "y": 1157.3604736328125 }, "pageIndex": 0, "pageNumber": 1 } ], "status": "cited" }, "match": "id_match", "pageIndex": 0, "pageNumber": 1, "source_bboxes": [ { "bbox": { "height": 22.6395263671875, "width": 100.3316650390625, "x": 285.6653137207031, "y": 1157.3604736328125 }, "pageIndex": 0, "pageNumber": 1 } ] }, "email": { "bbox": { "height": 28.07861328125, "width": 289.01318359375, "x": 877, "y": 1150.2880859375 }, "citation": { "confidence": { "groundedness": 0.9976200461387634 }, "regions": [ { "bbox": { "height": 28.07861328125, "width": 289.01318359375, "x": 877, "y": 1150.2880859375 }, "pageIndex": 0, "pageNumber": 1 } ], "status": "cited" }, "match": "id_match", "pageIndex": 0, "pageNumber": 1, "source_bboxes": [ { "bbox": { "height": 28.07861328125, "width": 289.01318359375, "x": 877, "y": 1150.2880859375 }, "pageIndex": 0, "pageNumber": 1 } ] } } }}Human review
Every value carries the evidence a reviewer needs, so automation can take the confident values and people can check the rest.
Each value in output.metadata points to its page and bounding box, so a reviewer can open the exact spot it came from.
Each citation carries a confidence score from 0 to 1 that shows how well the value is grounded in the document.
Send values with low confidence or no citation to a person, and pass the rest straight to the next system.
The same schema-based approach pulls fields from invoices, insurance claims and policies, KYC documents, lending files, and medical records.
Most common next steps
Use the following:
Get started:
Platform resources:
Nutrient is SOC 2 Type 2 audited annually. See the security documentation and privacy documentation for details on data handling.
All API communication uses HTTPS with TLS encryption. Unencrypted HTTP requests are rejected.
Nutrient extracts key-value pairs in one request. Post the form to the Data Extraction API extract endpoint with a JSON Schema that names the fields you need. Then read the values from output.data and their citations from output.metadata. The extract endpoint guide covers schemas and the response shape.
Nutrient’s Data Extraction API accepts PDFs (digital, scanned, and image-based), images, and Office files, including Word, Excel, and PowerPoint. For structured tabular rows, pair it with table extraction.
Nutrient’s key-value pair extraction uses the Data Extraction API extract endpoint. The endpoint returns only the fields you define in a JSON Schema, each with a citation. The parse endpoint of the same API returns the whole document instead, as Markdown or spatial JSON.
Yes, Nutrient’s extract endpoint returns the fields named in your schema. To see what a document contains before writing a schema, parse it to Markdown or spatial JSON first. The schema generator in Studio can also draft a schema from example documents.
Nutrient’s Data Extraction API is a REST API, so any language that sends HTTP requests can call it. This page has samples in shell, Windows shell, Python, and JavaScript.
Yes, Nutrient is SOC 2 Type 2 audited annually, and every request uses HTTPS. Unencrypted requests are rejected.
Nutrient’s extract endpoint bills two components per page: the parse mode and extraction. In understand mode, parsing costs 9 credits and extraction adds 6, so a page costs 15 credits. The free plan includes 5,000 Data Extraction credits each month. See Data Extraction API pricing.
Nutrient’s Data Extraction API scores 0.93 parsing accuracy in understand mode (the mode these samples use) on opendataloader-bench, a public set of 200 PDFs. That score comes from Nutrient’s internal test of the latest engine, run every night on the same public PDFs, so it can include improvements that haven’t reached the live API yet. It isn’t independently verified, and the Data Extraction benchmarks show every mode. Field-level accuracy depends on the document, so each value’s citation and confidence score show which values to check.
Create an account to get your Data Extraction API key and start making API calls.