Extraction pulls typed fields out of a document against a JSON schema we define, returning each leaf tagged with its own confidence score. For raw Markdown or just a category label instead, see the Parse quickstart or the Classification quickstart.
/v2/extract, waits for the job to finish, and writes the matched fields back as a clean JSON object with per-field confidence scores. Grab the full script from the dropdown below if you’d rather skip the walkthrough.
Show the Full Script
Show the Full Script
Set
UNSILOED_API_KEY in your environment and save the document you want to extract from as document.pdf in the same directory before running.- Python
- JavaScript
- cURL
extract_document.py
Step 1: Set Up Your Environment
Before writing any code, we need three things: an API key, a document, and the runtime for our chosen language.1.1 Get an Unsiloed AI API Key
To get API access, sign up on Unsiloed AI. Export your key as an environment variable namedUNSILOED_API_KEY so it stays out of source control:
1.2 Pick a Document to Extract Fields From
The/v2/extract endpoint supports PDF, DOCX, PPTX, JPG, PNG, and other formats. The walkthrough below assumes a PDF saved as document.pdf in your working directory. To use a different format, update the filename in the snippets to match your file.
If you don’t have a document handy, download our sample invoice PDF (a one-page invoice from Northwind Office Supplies with five line items) and save it as document.pdf. The schema in this guide targets the vendor, invoice number, issue date, total, and the line item table on that invoice.
1.3 Install Dependencies
- Python
- JavaScript
- cURL
You need Python 3.8 or newer. Install the
requests package:Step 2: Submit a Document With a Schema
The request bundles two fields:pdf_file for the document and schema_data for the JSON schema as a string. The schema is the interesting half. Anything we describe there, from a single total to a nested array of line items, comes back typed and scored in the exact shape we asked for. The endpoint returns a job_id we can poll. All requests go to https://prod.visionapi.unsiloed.ai with the API key in the api-key header.
2.1 Set Up the Script
- Python
- JavaScript
- cURL
Create a file called
extract_document.py and start with the imports and configuration:extract_document.py
API_KEY reads your key from the environment so it doesn’t get hard-coded into the file, and BASE_URL points at the Unsiloed AI production endpoint. Both appear in every request below.2.2 Define the Schema
The schema tells the API which fields to pull out and what shape they should take. The clearer thedescription on each field, the better the model locates and types each value. For our sample invoice, we want the vendor name, the invoice number, the issue date, the total due, and the five rows of the line item table.
- Python
- JavaScript
- cURL
Continue the file by defining the schema as a Python dict:The schema is plain JSON Schema with strict-mode rules:
extract_document.py
additionalProperties: false at every object level (which prevents the model from inventing fields we didn’t ask for), and a required list naming the must-have fields. See the Schemas reference for the full ruleset.2.3 Upload the Document
Send the file and the schema as a multipart upload to/v2/extract. The endpoint expects the document under the form field name pdf_file and the schema under schema_data (as a JSON string).
- Python
- JavaScript
- cURL
Next, upload the document and the schema together:The
extract_document.py
raise_for_status() call throws an HTTPError on any non-2xx response, so we don’t need to check .status_code ourselves. The json.dumps(schema) call serializes the dict because the endpoint expects schema_data as a string, not a nested form field.2.4 Capture the Job ID
- Python
- JavaScript
- cURL
Then read and print the Run the script:The output should be a single line like
job_id:extract_document.py
Job submitted: a90e48c4-f564-435e-9bf2-ab6eb5a0376d.Step 3: Poll for Results
The job runs asynchronously. We GET/extract/{job_id} repeatedly until the status is completed, then save the extracted fields to disk.
A status of completed means the result is ready; failed means the job errored; any other value (queued, processing, and so on) means the job is still running.
3.1 Write the Polling Loop
- Python
- JavaScript
- cURL
Next, drop in a polling loop. The
max_attempts cap stops the loop if the job hangs:extract_document.py
3.2 Save the Extracted Fields
Finally, persist the result to disk. The response is already structured JSON, so we write it straight toresult.json.
- Python
- JavaScript
- cURL
Finally, write the result to disk:Run the script:You should see a few
extract_document.py
Status: processing lines, then Status: completed, then the summary line. The result.json file appears in the working directory.Error Responses
Failures fall into two buckets: HTTP errors raised before the job is queued, and afailed status on a job that started but couldn’t complete.
HTTP Errors
The/v2/extract endpoint returns JSON bodies on HTTP errors, with a single detail field describing the problem. The common cases:
401 Unauthorized: body is{"detail": "Invalid API key"}. Theapi-keyheader is missing or wrong.400 Bad Request(missing file): body is{"detail": "Either pdf_file or file_url must be provided"}. Thepdf_fileform field is missing.400 Bad Request(bad JSON): body is{"detail": "schema_data must be valid JSON"}. Theschema_datafield isn’t parseable JSON.400 Bad Request(unreadable PDF): body starts with{"detail": "Error extracting data with citations: Failed to get PDF page count..."}. The uploaded file isn’t a valid PDF.422 Unprocessable Entity: body lists the missing or malformed form fields. Usually thrown whenschema_datais absent.404 Not Found: body is{"detail": "Job <id> not found"}. Thejob_idyou polled doesn’t exist.
Failed Jobs
A job that was accepted but couldn’t be processed comes back withstatus: "failed" on a subsequent poll. The response shape mirrors a completed one, with an error field describing what went wrong:
Response Shape
A completed response contains job metadata plus aresult object with one entry per top-level field in your schema. Each entry has the extracted value and a score between 0 and 1. For arrays of objects, the array itself has a score, and every property inside each row carries its own score as well.
result.{field_name}.value: the extracted data, typed to match your schema (string,number,boolean,object, orarray)result.{field_name}.score: confidence score between 0 and 1, higher is better. Use it to flag uncertain values for human review.result.{array_field}.value[].{property}.citation: reserved slot for source citations on array rows;nullfor now
metadata.schema: an echo of the schema you submitted, useful for round-tripping or auditingmetadata.order: the original order of top-level fields in your schema, since JSON objects don’t preserve insertion order across all clientsmetadata.page_count: number of pages in the uploaded document
job_id: unique identifier for the extraction jobstatus:completed,failed, or an in-progress value (queued,processing)file_name: name of the uploaded filefile_url: temporary signed S3 URL to the uploaded filecreated_at,updated_at: ISO 8601 timestamps for submission and the most recent status change
Sample Output
Running the script against the sample invoice writes the JSON above toresult.json. Every field comes back with its own confidence score, so flagging uncertain values becomes a per-field check rather than a re-read of the document. The fields extracted from the sample:
| Field | Extracted value | Confidence |
|---|---|---|
vendor_name | Northwind Office Supplies | 96% |
invoice_number | INV-2026-00487 | 97% |
issue_date | April 14, 2026 | 98% |
total_due | 3705.10 | 96% |
line_items | 5 rows | 98% |
line_items, each a structured object in its own right:
| Description | Quantity | Unit Price | Subtotal |
|---|---|---|---|
| Ergonomic Mesh Office Chair | 4 | 289.00 | 1,156.00 |
| Adjustable Standing Desk (60” x 30”) | 2 | 549.00 | 1,098.00 |
| LED Desk Lamp with USB Charging | 6 | 42.50 | 255.00 |
| Acoustic Panel, 24” Hexagon (Pack of 4) | 3 | 78.00 | 234.00 |
| Wireless Mechanical Keyboard | 5 | 129.99 | 649.95 |
Next Steps
For more on extraction, including schema rules, supported types, and the full response reference, see the Extract overview.
Schemas
JSON Schema rules, supported types, and worked examples for invoices and SEC filings.
Response Format
The canonical extraction response with a field-by-field reference.
API Reference
Browse the full request and response specs for
/v2/extract.FAQ
Check limits, supported formats, and answers to common questions.

