Introducing rakedoc-nano: a state-of-the-art open-weight VLM for document parsing
Split

Split one file into many.

A packet arrives as one file. It leaves as separate files. Each piece knows what it is and which pages it came from.

How it works

Classify decides. Split cuts.

We keep the two apart on purpose. One of them thinks, so it can be wrong. The other moves bytes, so it cannot.

  1. 01

    Find where each document starts

    Classify reads the packet page by page. It marks the first page of each document. That is a bigger deal than it sounds. An invoice followed by another invoice looks identical on every page.

    POST /v1/classifygranularity: pagedocumentStart
  2. 02

    Read the plan before you pay for it

    Set materialize to false. You get the page ranges and no files. Nothing is created and nothing is billed. Read the ranges. Move a boundary, or decide the packet was one document all along.

    materialize: falseconfidence: 0-5
  3. 03

    Cut. No model in the room.

    Split runs no model. It copies pages into new files. That is the whole job. Each child keeps the parent metadata and points back at the file it came from. Call it twice and you still get one set of files.

    POST /v1/splitparentFileIdidempotency-key
  4. 04

    Hand the pieces to the next step

    You get a flat list of file ids. Paste it into extract, or redact, or sign. The 100-segment ceiling matches the limit downstream, so one packet always fits in one call.

    output.documentIdsmax 100 segments
What it handles

Messy in. Addressable out.

Scanned, born-digital, or recorded. The boundaries come from the pages themselves, not from a filename that nobody keeps clean.

Packets up to 750 pages
One PDF per run. Up to 50 MB, 750 pages, and 100 pieces. Leave gaps if you want. The pages nobody asked for stay behind.
Scans, not just text layers
Born-digital pages get read directly. Scans go through OCR first. Either way we read the packet once, so you never pay twice for the same page.
Layout, not line breaks
Parsing returns blocks with a page and a position. A table that runs over a page break stays one table. It does not turn into a new document.
Recordings, by segment
Audio gets transcribed with speaker labels first. The transcript comes back in timed segments. That is where the natural cuts already are.
Wait, or don't
A small packet comes back finished. A 300-page one comes back with a status URL. Replay the same idempotency key and nothing gets cut twice.
Priced per page cut
Split is the cheap half of the pair, because deterministic work is cheap. Bring your own ranges and you skip classification, so no model runs at all.
Let's talk accuracy

A bad cut is a bad decision, not a bad knife.

So the decision carries the score, the threshold, and the place where a person steps in.

  • Boundaries
    What people assume Splitting a packet is a model problem.
    What happens Deciding is. Cutting is not. Classify makes every judgment call. Split runs no model, so it holds no opinion to get wrong.
  • Confidence
    What people assume You get a percentage and a shrug.
    What happens Every page gets a score from 0 to 5. A segment takes the lowest score inside it. The one shaky page is exactly where the boundary is wrong.
  • Review
    What people assume You find out downstream, in a support ticket.
    What happens Send anything at 3 or below to a person, before the cut. The gap between classify and split is a real stopping point, not an afterthought.
  • Tuning
    What people assume Collect examples. Retrain. Wait two weeks.
    What happens There is no training set to collect. You tune with a sentence. Describe the class better, re-run the page, and see the change now.
Packet shapes

The files nobody wants to open.

Each one arrives as a single upload. Each one holds half a dozen documents that belong to different people.

Vendor invoice runs
A month of invoices, scanned in one pass. Every page is the same class. The only clue is where one total ends and the next header starts.
Insurance claim files
Loss report, estimate, photos, police report, letters. One claim number, and five people who each need one part of it.
Patient intake forms
Consent, history, insurance card, referral letter. Faxed as one long file, because a fax machine has never heard of files.
Contract packages
Master agreement, schedules, order form, signature pages. Your team reads the schedules. Nobody enjoys scrolling to find them.
Loan and mortgage files
Pay stubs, tax forms, statements, appraisal, ID. Stapled into one PDF by a borrower who was doing their best.
Recorded calls
An hour with a claimant covers intake, the loss, coverage, and next steps. Four subjects, four owners, one recording.
Shipping and customs files
Commercial invoice, packing list, bill of lading, certificate of origin. Four documents in one PDF, and three systems that each want a different one.
Month-end statement runs
Twelve months of statements, downloaded as one file. Same layout on every page. A new month starts wherever the last balance ends.
Court filings with exhibits
The motion, the affidavit, and thirty exhibits, filed as one scan. Each exhibit needs its own number and its own page range.
For the engineers in the room

Split is boring. That is the feature.

No model runs in the cut. Same packet, same ranges, same files, every time. You can retry it, cache it, and reason about it at 2 a.m. When a cut looks wrong, it went wrong one call earlier, in classify. And classify hands you a score and a page number to prove it.

The interesting part sits in that earlier call. That is where the score lives, where a person can step in, and where one better sentence changes the result. We would rather keep the guesswork in one place than spread it across two.

Three ways in

Same cut. Different day job.

The three paths differ in who holds the page ranges. What comes out is identical.

For developers
Two calls and a free dry run. Pass a classify run and let us find the boundaries, or pass your own ranges when your system already knows them. That second path runs no model and bills no classification. Python and TypeScript SDKs, plus samples you can paste.
See the API
For teams
Nobody should click a Split button. It runs as a step inside an automation. The packet arrives, the pieces land in the right space, and the queue your team opens already has one document per row.
See the Workspace
For agents
One MCP connection gives an agent the whole API. It can classify, read the ranges, decide the packet was one document after all, and cut only then. Judgment first, bytes second.
See Agents
Show me the code

Two calls to cut. One to use the pieces.

Classify the pages, then cut on the boundaries. That is the whole capability. The third call below is extract, because every piece is its own file now. Look at the ranges between the first two calls.

import { CloudRakerClient } from "@cloudraker/api";

const client = new CloudRakerClient({ token: "YOUR_API_KEY" });
const packet = { url: "https://example.com/intake-packet.pdf" };

// 1 - Find where each document starts, page by page
const classified = await client.classify({
  body: {
    file: packet,
    granularity: "page",
    classes: [
      { id: "invoice", description: "A vendor invoice with a total due." },
      { id: "w9", description: "An IRS Form W-9." },
      { id: "agreement", description: "A signed services agreement." },
    ],
  },
});

// 2 - Cut the packet on those boundaries (no model runs here)
const run = await client.split({
  body: { file: packet, classifyRunId: classified.id },
});

for (const piece of run.output.splits) {
  console.log(piece.classId, piece.startPage, piece.endPage, piece.confidence);
}

// 3 - Every child is addressable on its own
const data = await client.extract({
  body: {
    files: run.output.documentIds.map((id) => ({ id })),
    schema: {
      type: "object",
      properties: { total_due: { type: ["number", "null"] } },
    },
    citations: true,
  },
});
console.log(data.output?.value);
from cloudraker.client import CloudRaker

client = CloudRaker(token="YOUR_API_KEY")
packet = {"url": "https://example.com/intake-packet.pdf"}

# 1 - Find where each document starts, page by page
classified = client.classify(
    file=packet,
    granularity="page",
    classes=[
        {"id": "invoice", "description": "A vendor invoice with a total due."},
        {"id": "w9", "description": "An IRS Form W-9."},
        {"id": "agreement", "description": "A signed services agreement."},
    ],
)

# 2 - Cut the packet on those boundaries (no model runs here)
run = client.split(file=packet, classify_run_id=classified.id)

for piece in run.output.splits:
    print(piece.class_id, piece.start_page, piece.end_page, piece.confidence)

# 3 - Every child is addressable on its own
data = client.extract(
    files=[{"id": file_id} for file_id in run.output.document_ids],
    schema={
        "type": "object",
        "properties": {"total_due": {"type": ["number", "null"]}},
    },
    citations=True,
)
print(data.output.value)
Where to go next

Split is one of many.

Same foundation under each one. Pick the door that fits how you work.

Automation
Put Split in a workflow with triggers, rules, and approvals. The packet gets cut before anyone has to open it.
See automation
Get started

Try it dry. Looking is free.

Point Split at a packet with materialize off. Read the ranges it proposes. If they look right, cut. If they do not, sharpen one sentence and run it again.