Classify
Classify decides. Split cuts. POST /v1/classify is the only one of the two that calls a model: it reads the parsed text and answers with a class id you chose. POST /v1/split calls no model at all — it takes page ranges and cuts the PDF.
Classify accepts any parseable file — PDF, office, image, audio, video.
Two granularities
Page mode is what feeds split. Document mode is for routing: branch a workflow, pick an extraction schema.
Classes are descriptions, not training data
A class is {id, description}. There is no labelled sample set, no training step and no display name. The description is the accuracy lever — write it the way you would brief a new hire.
classesis required: 2 to 50 entries.idmatches^[a-z0-9][a-z0-9_-]{0,63}$and is unique. It is your only branch key.descriptionis at most 500 characters.- One class must be the catch-all. The convention is
id: "other". If you send none, CloudRaker injects{"id": "other", "description": "None of the above."}and echoes the effective config back on the run. A closed set with no exit makes the model guess.
Quickstart — document mode
Example response — document mode
config.classes echoes the effective class list, with the catch-all injected if you left it out.
output.classId, output.confidence and output.reasoning describe the first document, for the one-file case. output.documents[] is authoritative when you send files: [...]. This mirrors extract.
Page mode
Send "granularity": "page" to get a label per page and the segments derived from it.
pages[]is the model’s raw answer.pageis 1-based.- Boundaries come from
documentStart, not from a change of class. That is what separates an invoice followed by another invoice — the most common packet shape there is. Pages 1–3 and 4–5 above are bothinvoiceand are still two documents. segments[]is derived in code fromdocumentStart, then a segment shorter thanrules.minPagesmerges into the one before it (index 0 merges forward).startPage/endPageare 1-based inclusive, contiguous and non-overlapping.- A segment’s
confidenceis the minimum of its pages’ — one uncertain page inside a segment is exactly where a boundary is wrong. unassignedPagesis normally[]. It reports any page the repair pass could not place.
Page mode needs per-page structure. A source that only produced markdown answers document mode but fails page mode with insufficient_text.
The pipeline is three calls
Three, not two — on purpose. Between step 1 and step 2 you can inspect the segments, override them, or skip split entirely when the answer is “this whole file is one invoice”. Route on classId: that is what a stable class id is for.
If you already know the ranges, skip step 1. Post segments to /v1/split directly and pay for no model call at all.
Configuration
The whole configuration must serialize under 16 KB. A file with more pages than pageRange allows fails with page_limit_exceeded — it is never silently truncated.
There is no minConfidence, no tier, no model and no per-class examples. Put your examples in the description.
Confidence
confidence is an integer 0–5, the same scale as citation confidence everywhere else on the platform.
A low confidence never rewrites the label. The model’s chosen class stands. “Unsure” and “sure it is other” have to stay distinguishable, or your routing code loses the only signal it has. You set the threshold.
reasoning is one short sentence of prose. It is not evidence, it is not grounded, and it carries no citations. Do not parse it.
What you pay for
Classify bills per page sent to the model, and usage itemizes it:
- Document mode bills only the first and last window — that is what decides whole-file identity.
usage.pagescounts the pages actually read, never the pages in the file. - Page mode bills every page in
pageRange. usage.parsecounts every parsed page. Parsing is always billed on top of classification.
Save it as a config
A taxonomy is usually organization-wide. Save it once and every call shrinks to {"file": …, "action": "mailroom"}:
GET, PUT and DELETE /v1/classify/configs/{idOrSlug} do the rest. See Saved configs.
There is no /v1/split/configs: split has nothing to configure.
Sync vs async
Behaviour matches extract. ?wait= accepts 0 to 120 seconds, default 60. A document-mode classify of a short file returns 200 inline. A page-mode classify of a long packet returns 202 with a run id — that is the contract, not an error. Pass ?wait=0 and poll, or use a webhook.