Jev AI Hub
Start Learning

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."
      }
    }
  }
}
EOF

Expected 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

  1. Primitives (Questions)TypeSafe · accessed 2026-09-20 · documentation
  2. API referenceTypeSafe · accessed 2026-09-20 · documentation
  3. Jev 1.13 jaggednessTypeSafe · 2026-09-17 · accessed 2026-09-20 · documentation

All Jev examples