Classification · Choice
Classify Documents with Jev
Document-type classification with Jev Choice. Different from customer intent: this page asks what the file is, not what the person wants.
- Published
- Sep 20, 2026
- Updated
- Sep 20, 2026
- Last verified
- Sep 20, 2026
Quick answer
Label an uploaded file as invoice, contract, resume, policy, or other from a text excerpt.
Problem
A shared inbox and a Drive folder collect PDFs that have already been turned into text. Downstream parsers are type-specific. You need a label before you run the invoice extractor.
Why Jev fits this task
File type is a closed set. Official primitives: Choice fits unordered labels such as document type. Add other so a novel memo is not forced into contract.
Input state
Send only the fields the questions name. Official docs warn that extra unrelated state costs accuracy.
{
"filename": "northline-q3.pdf",
"excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
}Question
What kind of document is this text excerpt?
Question type: Choice.
Jev schema
{
"model": "jev-latest",
"state": {
"filename": "northline-q3.pdf",
"excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
},
"questions": {
"doc_type": {
"type": "choice",
"instructions": "What type of document is `excerpt`, given `filename`?",
"criteria": {
"invoice": "A bill requesting payment, with amount and payee.",
"contract": "An agreement with parties, terms, or signature blocks.",
"resume": "A person's work history or skills for hiring.",
"policy": "Internal or public rules, not a bill or a person's CV.",
"other": "None of the above, or too little text to tell."
}
}
}
}Python example
from typesafe_sdk import Choice, TypeSafeClient
state = {
"filename": "northline-q3.pdf",
"excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15.",
}
with TypeSafeClient() as client:
response = client.system_one(
state=state,
questions={
"doc_type": Choice(
instructions="What type of document is `excerpt`, given `filename`?",
criteria={
"invoice": "A bill requesting payment, with amount and payee.",
"contract": "An agreement with parties, terms, or signature blocks.",
"resume": "A person's work history or skills for hiring.",
"policy": "Internal or public rules, not a bill or a person's CV.",
"other": "None of the above, or too little text to tell.",
},
),
},
)
print(response.answers["doc_type"].choice)
print(response.model)TypeScript example
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient();
const response = await client.systemOne({
state: {
"filename": "northline-q3.pdf",
"excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
},
questions: {
doc_type: choice("What type of document is `excerpt`, given `filename`?", {
invoice: "A bill requesting payment, with amount and payee.",
contract: "An agreement with parties, terms, or signature blocks.",
resume: "A person's work history or skills for hiring.",
policy: "Internal or public rules, not a bill or a person's CV.",
other: "None of the above, or too little text to tell.",
}),
},
});
console.log(response.answers.doc_type.choice);
console.log(response.model);JavaScript example
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient();
const response = await client.systemOne({
state: {
"filename": "northline-q3.pdf",
"excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
},
questions: {
doc_type: choice("What type of document is `excerpt`, given `filename`?", {
invoice: "A bill requesting payment, with amount and payee.",
contract: "An agreement with parties, terms, or signature blocks.",
resume: "A person's work history or skills for hiring.",
policy: "Internal or public rules, not a bill or a person's CV.",
other: "None of the above, or too little text to tell.",
}),
},
});
console.log(response.answers.doc_type.choice);
console.log(response.model);cURL example
curl -s https://api.typesafe.ai/v1/systemone \
-H "Authorization: Bearer $TYPESAFE_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'EOF'
{
"model": "jev-latest",
"state": {
"filename": "northline-q3.pdf",
"excerpt": "Invoice #1842. Bill to Northline Logistics. Description: September platform fee. Amount due: $2,400. Net 15."
},
"questions": {
"doc_type": {
"type": "choice",
"instructions": "What type of document is `excerpt`, given `filename`?",
"criteria": {
"invoice": "A bill requesting payment, with amount and payee.",
"contract": "An agreement with parties, terms, or signature blocks.",
"resume": "A person's work history or skills for hiring.",
"policy": "Internal or public rules, not a bill or a person's CV.",
"other": "None of the above, or too little text to tell."
}
}
}
}
EOFExpected output
{
"model": "jev-1.13.0",
"answers": {
"doc_type": {
"type": "choice",
"choice": "invoice",
"probabilities": {
"invoice": 0.93,
"contract": 0.03,
"resume": 0.01,
"policy": 0.01,
"other": 0.02
},
"confidence": 0.91
}
},
"usage": {
"input_tokens": 230,
"output_tokens": 32
}
}Confidence handling
Low confidence: quarantine the file. High-stakes mislabels (contract vs invoice) should use a higher bar than corpus tagging.
Production considerations
After you have a type, run type-specific extractors in code. If you need hierarchy (invoice > utility vs SaaS), official cookbooks describe beam search over nested Choices — that is a second request, not this page.
Intake pipelines, email attachments, and RAG corpus labeling.
When to use Jev
You have a stable taxonomy and a text excerpt.
When not to use Jev
You are classifying customer intent, routing a ticket, or asking 'is this spam?' — those are other examples.
Jev does not read the PDF bytes. OCR and page splitting stay in your pipeline. Official input: text only. Do not send a 64k dump of the whole book if the first page decides the type.
Common mistakes
- Using this URL for intent classification. Intent lives at /examples/intent-detection/.
- Sending scanned images without OCR.
FAQ
Can Jev classify 75 industry codes?
Official cookbooks show large Choice sets and confidence-based fallback to a parent label. Test your own taxonomy; do not assume a 75-way split is free of errors.
Sources
- Primitives (Questions)TypeSafe · accessed 2026-09-20 · documentation
- API referenceTypeSafe · accessed 2026-09-20 · documentation
- Jev 1.13 jaggednessTypeSafe · 2026-09-17 · accessed 2026-09-20 · documentation