This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/dws-data-extraction/classify.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Classify endpoint

The classify endpoint scores a document against a list of labels you supply and returns a ranked list of predictions:

POST https://api.nutrient.io/extraction/classify

Use the classify endpoint to decide where a document goes before you extract anything from it. A claim form, a medical report, and a cover letter are all “a PDF” until something reads them. Classify makes that call so an intake queue can route each file to the right destination. To pull fields out of a document once it’s routed, refer to the extract endpoint guide.

How classification works

Classification is zero-shot. The API scores the document against the labels in your request, not labels learned from a training set. There’s no model to train and no template to maintain. Switching to a new set of document types means sending a new label list.

Each document is scored two ways: once from its extracted text, and once from its page images. The two scores are merged into a single ranked list. Dedicated scoring models do the work, not a generative large language model (LLM) or vision language model (VLM).

Request formats

Every classify request needs at least two labels. Each label has a label name and an optional description. The description matters: The classifier scores against it as much as against the name, so a specific description gives a sharper boundary than a vague one.

Multipart form upload

Send the document as the file form field, and send the labels inside a JSON-serialized instructions field:

Terminal window
curl -X POST https://api.nutrient.io/extraction/classify \
-H "Authorization: Bearer your_api_key_goes_here" \
-F "file=@document.pdf" \
-F 'instructions={"labels":[{"label":"invoice","description":"A commercial invoice or bill."},{"label":"contract","description":"A legal agreement between parties."},{"label":"resume","description":"A résumé or CV from a job applicant."}]}'

JSON URL input

To classify a document that’s already reachable at a URL, send a JSON body with url and labels as top-level properties:

Terminal window
curl -X POST https://api.nutrient.io/extraction/classify \
-H "Authorization: Bearer your_api_key_goes_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://storage.example.com/contract.pdf",
"labels": [
{ "label": "invoice", "description": "A commercial invoice or bill." },
{ "label": "contract", "description": "A legal agreement between parties." }
]
}'

Request options

All options go alongside labels, inside the multipart instructions JSON or the top level of a JSON body.

OptionTypeDescription
labelsarrayRequired. At least two candidate labels. Each item has a label string and an optional description.
topKintegerMaximum number of ranked predictions to return. 0 or omitted returns all of them.
textWeightnumberSet to 0 to skip the text branch and its text extraction. Any other value between 0 and 1 is accepted but doesn’t change the result; the engine balances the two branches per document.
imageWeightnumberSet to 0 to skip the image branch and its page rendering. Any other value between 0 and 1 is accepted but doesn’t change the result; the engine balances the two branches per document.

Leave at least one branch enabled. With both weights set to 0, no branch produces a score.

Response

A successful request returns HTTP 200 with the top label, its score, and the full ranked list:

{
"status": 200,
"requestId": "req_cl_001",
"output": {
"classification": {
"label": "invoice",
"score": 0.92,
"predictions": [
{ "label": "invoice", "score": 0.92 },
{ "label": "contract", "score": 0.14 },
{ "label": "resume", "score": 0.03 }
]
}
},
"metrics": {
"processingTimeMs": 1840,
"pagesProcessed": 1
},
"usage": {
"data_extraction_credits": {
"cost": 1,
"remainingCredits": 4999
}
}
}
FieldDescription
output.classification.labelThe top-ranked label.
output.classification.scoreThe top label’s score. Present when the engine returns one.
output.classification.predictionsEvery candidate label with its score, highest first. topK caps the length of this list.
metrics.pagesProcessedThe number of pages scored. This is the number of credits the request cost.

Reading the scores

Each score is an independent confidence for that label, in the range 0 to 1. The scores aren’t a probability distribution and don’t sum to 1. A cover letter attached to a contract can legitimately score high on both correspondence and contract.

That independence is what lets a router flag an ambiguous document instead of forcing it into one bucket. Compare the top score with the runner-up, and send close calls to manual review:

def route(classification, routes, ambiguity_gap=0.15):
predictions = classification["predictions"]
top = predictions[0]
runner_up = predictions[1] if len(predictions) > 1 else None
if runner_up and top["score"] - runner_up["score"] < ambiguity_gap:
return "queue:manual-review"
return routes.get(top["label"], "queue:manual-review")

The threshold is yours to choose. Because the label list and the routes map are both parameters, the same function serves insurance intake, legal filings, or HR onboarding paperwork. For a complete worked example, refer to the document routing walkthrough.

Stored classifiers

You can save a label list as a classifier in the Data Extraction Studio(opens in a new tab) and run it by reference. Send processor with the classifier’s ID instead of labels, and optionally pin a published version. Add storeRun: true to keep the run in your processing history. Refer to the API reference(opens in a new tab) for the full request schema.

Pricing

Classify costs a flat 1 credit per page, independent of parse mode. A 10-page document costs 10 credits. Refer to the pricing guide for plan thresholds.

Supported file types

The API reference(opens in a new tab) lists four input types for classify: application/pdf, image/png, image/jpeg, and image/tiff. Office documents, which the parse and extract endpoints accept, aren’t listed for classify. Refer to the supported file types guide for the extensions and MIME types behind each format.

Errors

A request with fewer than two labels returns HTTP 400 with errorDetails.failingPaths pointing at $.labels. Failed requests always return a JSON body with a non-200 status and an errorMessage. Refer to the error handling guide for the full status code reference.

Try it

Open the Classify workbench in Studio(opens in a new tab) to run a document against your own labels before wiring the endpoint into a pipeline.