Skip to main content
Categorize splits a document into logical segments (or a spreadsheet into sheets) and classifies each against a taxonomy. Use it to route mixed uploads (“is this a bank statement, an invoice, or a lease?”), to split combined PDFs into their constituent documents, or to identify which sheets in a workbook contain what. You can bring your own taxonomy or use NDI’s default. Each classified segment also comes with a short summary and a markdown rendition of just that segment.
EndpointBehavior
POST /categorizeStarts the job and waits for the result (bounded by timeout_seconds).
POST /categorize_asyncStarts the job and returns 202 {"job_id": …} immediately.

Request

timeout_seconds
number
default:"120"
Sync endpoint only. Max seconds to wait, between 1 and 300.
file
object
required
The document to categorize. Same shape as everywhere else — source_url (+ file_name for s3:///https://). See Files & sources. Supported extensions are the same as parse.
taxonomy
object
The category vocabulary to classify against. Omit to use NDI’s default taxonomy (general business-document categories).
markdown_url
string
markdown_url from a prior parse of the same file (an s3:// URL returned by NDI). When present, categorize skips its internal parse and runs directly on the markdown — faster and cheaper if you already parsed the document.
idempotency_key
string
Up to 128 characters. See Idempotency.

Result

result_type
"categorize"
Discriminator — always "categorize".
status
"success" | "failed"
Outcome of the classification run; error carries detail on failure.
items
array
Classified units, tagged by kind. Documents yield document_segment entries (contiguous page ranges); spreadsheets yield sheet entries.

Examples

curl -s "$NDI_BASE/categorize" \
  -H "X-API-Key: $NDI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": { "source_url": "ndi://file/7f4d2a10-3b7e-4c25-9f61-8f0f4f0a1b2c" },
    "taxonomy": {
      "categories": [
        { "key": "bank_statement", "description": "Monthly statement from a bank listing transactions and balances." },
        { "key": "invoice", "description": "A bill issued to or by the company for goods or services." },
        { "key": "lease_agreement", "description": "A contract granting use of property or equipment for a period." },
        { "key": "general_ledger", "description": "Full ledger of journal entries by account." }
      ]
    },
    "idempotency_key": "categorize-batch-42"
  }'
curl -s "$NDI_BASE/categorize_async" \
  -H "X-API-Key: $NDI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": {
      "source_url": "https://example.com/mixed-upload.pdf",
      "file_name": "mixed-upload.pdf"
    }
  }'
Result
{
  "job_id": "e2f3a4b5-6c7d-4e8f-9a0b-1c2d3e4f5a6b",
  "action": "categorize",
  "status": "succeeded",
  "result": {
    "result_type": "categorize",
    "status": "success",
    "error": null,
    "items": [
      {
        "kind": "document_segment",
        "file_name": "mixed-upload.pdf",
        "page_start": 1,
        "page_end": 3,
        "category": "bank_statement",
        "is_freeform_category": false,
        "summary": "Checking-account statement for December 2025 from First National Bank, listing 84 transactions and an ending balance of $1,204,331.",
        "markdown_url": "https://…(time-limited)…/segment-0.md"
      },
      {
        "kind": "document_segment",
        "file_name": "mixed-upload.pdf",
        "page_start": 4,
        "page_end": 4,
        "category": "invoice",
        "is_freeform_category": false,
        "summary": "Invoice #2025-1187 from Acme Facilities for Q4 maintenance services, $18,500 due January 15, 2026.",
        "markdown_url": "https://…(time-limited)…/segment-1.md"
      }
    ]
  },
  "error": null,
  "created_at": "2026-07-12T21:20:05Z",
  "started_at": "2026-07-12T21:20:06Z",
  "completed_at": "2026-07-12T21:20:38Z"
}