Extract endpoint
The Nutrient DWS Data Extraction API extract endpoint returns domain-specific data from a document as JSON shaped to the schema you provide:
POST https://api.nutrient.io/extraction/extractUse the extract endpoint when you need specific values from a document. To return document structure, such as typed spatial elements or whole-document Markdown, refer to the parse endpoint guide. Provide a schema for fields such as invoice_number and total_amount, and the response returns those values from the document. You can also include per-field citations that point back to the source. To define the schema, refer to the define a schema guide. To configure citations, refer to the citations and confidence guide.
When to use extract vs. parse
Choose the endpoint based on the output your application needs.
| Use case | Endpoint |
|---|---|
| Pull known fields into a typed JSON object, such as invoices or forms | /extraction/extract |
| Get the full document as typed elements or Markdown | /extraction/parse |
| Map data to a downstream database or API contract | /extraction/extract |
| Support retrieval-augmented generation (RAG) ingestion, search indexing, or content migration | /extraction/parse |
If you need both raw structure and specific fields, use the extract endpoint. It runs a parse stage internally. To configure that stage, refer to the parse configuration guide.
Model customization and processing location
Customize extraction with your JSON Schema, field descriptions, and document-level instructions. The API doesn’t currently offer fine-tuning of a dedicated model on your documents or a customer-selectable underlying model.
Some AI inference for extract requests may run in the US as part of the broader processing pipeline, even when parseConfig selects a non-agentic mode. Refer to the privacy guide for processing regions, retention, and data protection terms.
Request formats
Every extract request must include a schema, unless it runs a stored preset. The request shape depends on how you provide the document:
- Multipart file upload — Send the document as the
fileform field, and send one outer multipartinstructionsfield whose value is JSON. That JSON containsschema, optionalparseConfig, and optional inner document-levelinstructionsguidance. - JSON URL input — Send a JSON body with
url,schema, optionalparseConfig, and optional document-levelinstructionsguidance as top-level JSON properties.
Do not send schema or parseConfig as separate multipart form fields. For multipart uploads, they must be inside the outer multipart instructions JSON field.
Multipart form upload
Upload a file with a JSON-serialized outer multipart instructions field:
curl -X POST https://api.nutrient.io/extraction/extract \ -H "Authorization: Bearer your_api_key_goes_here" \ -F "file=@invoice.pdf" \ -F 'instructions={"schema":{"type":"object","properties":{"invoice_number":{"type":"string","description":"Invoice identifier"},"total_amount":{"type":"number","description":"Total amount including tax"}},"required":["invoice_number","total_amount"]},"parseConfig":{"mode":"understand"},"instructions":"Treat shipping and handling as separate line items."}'import json
import requests
schema = { "type": "object", "properties": { "invoice_number": {"type": "string", "description": "Invoice identifier"}, "total_amount": {"type": "number", "description": "Total amount including tax"}, }, "required": ["invoice_number", "total_amount"],}
outer_instructions = { "schema": schema, "parseConfig": {"mode": "understand"}, "instructions": "Treat shipping and handling as separate line items.",}
with open("invoice.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(outer_instructions)}, )
print(response.json()["output"]["data"])import fs from "node:fs";
const schema = { type: "object", properties: { invoice_number: { type: "string", description: "Invoice identifier" }, total_amount: { type: "number", description: "Total amount including tax" }, }, required: ["invoice_number", "total_amount"],};
const outerInstructions = { schema, parseConfig: { mode: "understand" }, instructions: "Treat shipping and handling as separate line items.",};
const form = new FormData();form.append("file", await fs.openAsBlob("invoice.pdf"), "invoice.pdf");form.append("instructions", JSON.stringify(outerInstructions));
const response = await fetch("https://api.nutrient.io/extraction/extract", { method: "POST", headers: { Authorization: "Bearer your_api_key_goes_here" }, body: form,});
const result = await response.json();console.log(result.output.data);The JavaScript samples use fs.openAsBlob, which requires Node 19.8 or later.
JSON body with URL
Process a document hosted at a public URL by sending url, schema, parseConfig, and optional document-level instructions as JSON:
curl -X POST https://api.nutrient.io/extraction/extract \ -H "Authorization: Bearer your_api_key_goes_here" \ -H "Content-Type: application/json" \ -d '{ "url": "https://storage.example.com/invoice.pdf", "schema": { "type": "object", "properties": { "invoice_number": { "type": "string", "description": "Invoice identifier" }, "total_amount": { "type": "number", "description": "Total amount including tax" } }, "required": ["invoice_number", "total_amount"] }, "parseConfig": { "mode": "understand" }, "instructions": "Treat shipping and handling as separate line items." }'import requests
response = requests.post( "https://api.nutrient.io/extraction/extract", headers={ "Authorization": "Bearer your_api_key_goes_here", "Content-Type": "application/json", }, json={ "url": "https://storage.example.com/invoice.pdf", "schema": { "type": "object", "properties": { "invoice_number": {"type": "string", "description": "Invoice identifier"}, "total_amount": {"type": "number", "description": "Total amount including tax"}, }, "required": ["invoice_number", "total_amount"], }, "parseConfig": {"mode": "understand"}, "instructions": "Treat shipping and handling as separate line items.", },)
print(response.json()["output"]["data"])const response = await fetch("https://api.nutrient.io/extraction/extract", { method: "POST", headers: { Authorization: "Bearer your_api_key_goes_here", "Content-Type": "application/json", }, body: JSON.stringify({ url: "https://storage.example.com/invoice.pdf", schema: { type: "object", properties: { invoice_number: { type: "string", description: "Invoice identifier" }, total_amount: { type: "number", description: "Total amount including tax" }, }, required: ["invoice_number", "total_amount"], }, parseConfig: { mode: "understand" }, instructions: "Treat shipping and handling as separate line items.", }),});
const result = await response.json();console.log(result.output.data);Instruction fields
The extract endpoint accepts these fields. In multipart requests, put them inside the outer multipart instructions JSON field. In JSON URL requests, put them at the top level of the JSON body.
| Field | Type | Description |
|---|---|---|
schema | object | Required unless the request uses a stored preset — JSON Schema that describes the data to extract. The root type must be object. Refer to the define a schema guide. |
instructions | string | Optional inner document-level free-text guidance for the extraction model, up to 10,000 characters. This is different from the outer multipart instructions field. |
parseConfig | object | Optional configuration for the parse stage that runs before extraction. Refer to the parse configuration guide. |
options | object | Extract-specific response options, such as includeCitations. Refer to the citations and confidence guide. |
Response structure
A successful response returns extracted data, optional per-field metadata citations, and pages:
{ "status": 200, "requestId": "req_x1y2z3w4", "output": { "data": { "invoice_number": "INV-2024-0042", "total_amount": 1547.5 }, "metadata": {}, "pages": [{ "page": 1, "width": 1200, "height": 1697 }] }, "metrics": { "processingTimeMs": 4800, "pagesProcessed": 1 }, "usage": { "data_extraction_credits": { "cost": 15, "remainingCredits": 835 }, "price_composition": { "parse": { "units": 1, "unit_cost": 9, "cost": 9, "currency": "data_extraction_credits" }, "extract": { "units": 1, "unit_cost": 6, "cost": 6, "currency": "data_extraction_credits" } } }}The response includes these top-level output fields:
output.data— Extracted values shaped to your schema. The API returns only declared properties.output.metadata— Per-field citation metadata that mirrors the structure ofoutput.data. This object is empty when citations are disabled.output.pages— Page metadata, including the dimensions citation coordinates use.metrics— Processing time and pages processed.usage— Total credits consumed, broken down into parse and extract components. For credit details, refer to the pricing guide.
Stored presets
A preset stores your schema, instructions, and parse configuration so you can run them by reference instead of sending them with every request. To create or update a preset, follow these steps in Data Extraction Studio(opens in a new tab):
- Open the Configuration tab, scroll to the top of the panel, and select Presets next to the preset name.
- Choose Save as new preset to create a preset, or Save changes to update the preset you have open.
- Select Presets again and choose Publish. Publish stays unavailable until you save your changes.
To run a preset, reference it by ID instead of sending schema, parseConfig, options, and document-level instructions. For multipart uploads, put processor inside the outer multipart instructions field, for example instructions={"processor":"proc_…"}. For JSON requests, send processor as a top-level property alongside url. A request can’t combine a preset with inline configuration. Optionally, specify a published version number using version.
If you omit version, the API uses the latest published version. Saving subsequent edits doesn’t make them available through the API until you publish them.
version accepts a positive integer or "latest". The API returns 400 when a request combines processor with inline configuration, and 422 when the preset or version doesn’t exist or isn’t published.
To keep the run in your processing history, add storeRun: true alongside processor. For stored runs, the response includes runId and an X-Nutrient-Run-Id header. Refer to the API reference for the full request schema.
Run asynchronously
For long documents, or when the caller can’t hold a connection open, send the same request to POST /extraction/extract/async. It answers 202 with a stored run you poll for the result. Stored presets work the same way on the asynchronous endpoint. Refer to the run asynchronously guide.
Next steps
Use these guides to continue working with the extract endpoint.
- Refer to the define a schema guide for supported JSON Schema keywords, constraints, and size limits.
- Refer to the parse configuration guide to control the parse stage with
parseConfig.modeand language hints. - Refer to the citations and confidence guide to ground extracted values back to the source document.
- Refer to the production structured extraction guide to configure strict output, validation, confidence gates, and audit logging.
- Refer to the error handling guide for status codes and error response formats.