Extract invoice data with an API
Describe the fields you want; get them back as JSON with a confidence score for each one.
The ASHDOCS invoice data extraction API reads a supplier invoice PDF and returns the fields you ask for as JSON. You send a schema, such as vendor_name, invoice_number, invoice_date, total_amount and a line_items array, and the response gives you the values plus a confidence score between 0 and 1 for every field.
It is built for accounts-payable automation: pull bills out of an inbox or a shared folder, extract them, and send only the uncertain ones to a person. It works on text PDFs; scanned documents need OCR first (ask us).
curl -X POST https://www.ashdocs.com/api/v1/extract/data \
-H "X-API-Key: ash_test_..." \
-H "Content-Type: application/json" \
-d '{
"file_url": "https://example.com/bills/inv-1042.pdf",
"schema": {
"vendor_name": { "type": "string" },
"invoice_number": { "type": "string" },
"invoice_date": { "type": "date" },
"total_amount": { "type": "number" },
"line_items": {
"type": "array",
"items": {
"description": { "type": "string" },
"quantity": { "type": "number" },
"unit_price": { "type": "number" }
}
}
},
"confidence_threshold": 0.85
}'const res = await fetch("https://www.ashdocs.com/api/v1/extract/data", {
method: "POST",
headers: { "X-API-Key": "ash_test_...", "Content-Type": "application/json" },
body: JSON.stringify({
file_url: "https://example.com/bills/inv-1042.pdf",
schema: {
vendor_name: { type: "string" },
invoice_number: { type: "string" },
invoice_date: { type: "date" },
total_amount: { type: "number" },
line_items: {
type: "array",
items: {
description: { type: "string" },
quantity: { type: "number" },
unit_price: { type: "number" },
},
},
},
confidence_threshold: 0.85,
}),
});
const result = await res.json();
if (result.needs_review) console.log("check", result.confidence);
const extracted = await (await fetch(result.outputs[0].url)).json();
console.log(extracted.data);import requests
r = requests.post(
"https://www.ashdocs.com/api/v1/extract/data",
headers={"X-API-Key": "ash_test_..."},
json={
"file_url": "https://example.com/bills/inv-1042.pdf",
"schema": {
"vendor_name": {"type": "string"},
"invoice_number": {"type": "string"},
"invoice_date": {"type": "date"},
"total_amount": {"type": "number"},
"line_items": {
"type": "array",
"items": {
"description": {"type": "string"},
"quantity": {"type": "number"},
"unit_price": {"type": "number"},
},
},
},
"confidence_threshold": 0.85,
},
)
result = r.json()
extracted = requests.get(result["outputs"][0]["url"]).json()
print(extracted["data"], result["needs_review"]){
"success": true,
"request_id": "req_3e9a1c7b0d42",
"job_id": "job_71d0b5e2c9a8",
"status": "completed",
"credits_consumed": 0,
"outputs": [
{
"filename": "extracted.json",
"size": 1184,
"url": "<signed URL to {data, confidence}, valid for 1 hour>",
"expires_at": "2026-10-09T13:00:00+00:00"
}
],
"confidence_summary": { "overall": 0.93, "min": 0.6, "flagged": 1, "total": 9 },
"needs_review": true,
"result_id": "xres_9f2c4e1a7b30",
"confidence": {
"vendor_name": 0.98,
"invoice_number": 0.97,
"invoice_date": 0.95,
"total_amount": 0.6,
"line_items": [{ "description": 0.96, "quantity": 0.97, "unit_price": 0.95 }]
}
}Response trimmed; values illustrative. The extracted values are in the first output file. Test keys report 0 credits; a live key reports 3.
Your schema, your field names
Ask for exactly the fields your ledger or approval flow needs, with string, number, date and array types. Missing fields come back as null, never guessed.
Confidence on every field
Each value carries a 0–1 score, lowered automatically when a date does not parse, a number is not numeric, or the line items do not add up to the total.
A review step built in
Results below your threshold are flagged needs_review and land in the dashboard review queue. Approving a correction fires a review.approved webhook on paid plans.
How the invoice data extraction API works
Call POST /api/v1/extract/data with a JSON body holding a schema and a file_url the service can download, or upload the PDF directly to POST /api/v1/tools/pdf-to-data as multipart with the schema in options. The text is read from the PDF page by page, and a language model fills in your schema from that text with an instruction to set missing fields to null rather than invent them.
The values are then checked: a field typed date that is not a valid date, or a number that is not numeric, has its confidence capped, and if line_items quantity times unit price differs from total_amount by more than 5%, the total's confidence is capped too. The lowest score is compared with your confidence_threshold (0.85 by default) to set needs_review.
on_low_confidence:flag(default) marks the result,failreturns a 422,ignorekeeps it out of the review queue.retention: "zero"skips the stored review-queue record; the response then carries the confidence summary, and per-field scores stay in extracted.json.- Cost: 3 credits per document on a live key; test keys never use credits.
Fields for accounts payable
There is no fixed list: you get the fields your schema names. The built-in Invoice → QuickBooks JSON pipeline template uses a schema you can copy as a starting point.
| Field | Type |
|---|---|
| vendor_name | string |
| invoice_number | string |
| invoice_date, due_date | date |
| subtotal, tax, total_amount | number |
| line_items[]: description, quantity, unit_price | array of objects |
Scanned invoices and photos
Extraction reads the text layer of a PDF and accepts PDF files only. A scan or a phone photo has no text layer, so run it through the OCR tool (POST /api/v1/tools/ocr, 3 credits, accepts PDF, JPG, PNG and TIFF) first, then extract from the searchable PDF it returns. If you are processing scans in volume, ask us and we will help you set the pipeline up.
Frequently asked questions
How accurate is invoice data extraction?
We do not publish an accuracy percentage because we have not measured one we could stand behind. Instead every field comes back with a confidence score from 0 to 1, scores are lowered when values fail type or arithmetic checks, and anything below your threshold is flagged needs_review so a person can check it.
Which fields are extracted?
The fields you name in your schema, with string, number, date and array types. A typical accounts-payable schema asks for vendor_name, invoice_number, invoice_date, due_date, subtotal, tax, total_amount and line_items with description, quantity and unit_price.
Does it handle scanned invoices?
Not directly. Extraction reads the text layer of a PDF, so a scan has to go through OCR first; ask us and we will help you set that up. The OCR tool turns a scanned PDF or image into a searchable PDF, which you then send to extraction as a second step.
How do I validate the results?
Check needs_review and the per-field confidence in the response, and route anything below your threshold to a person. Results that need review appear in the dashboard review queue, where approving a correction fires a review.approved webhook on paid plans; set on_low_confidence to fail if you would rather reject low-confidence results outright.
Plans
- 100 credits per month
- 1 seat
- No webhooks
- 1,500 credits per month
- 1 seat
- Webhooks
- 10,000 credits per month
- 3 seats
- Webhooks
- 30,000 credits per month
- 5 seats
- Webhooks
- 100,000 credits per month
- 10 seats
- Webhooks
Test keys are free, never expire and never use credits; plan rate limits apply. Webhooks are on paid plans. Issuing an invoice uses 1 credit. No per-seat fees. See full pricing.