Introducing RakeSign: Free, Unlimited Document Signing

Information extracted, one lease record.

The lease, the abstract and the fact sheet all describe the same property, and they do not always agree. Send them together, get one cited record back, and see exactly which document won each contested field.

The problem

One property. Four versions of the truth.

A commercial lease is never one document. There is the signed lease, an abstract someone typed up two years ago, a broker's fact sheet, and a spreadsheet the asset manager keeps. Each one states the rent. They do not all state the same rent.

So someone opens all four, finds the disagreements, decides which to believe, and types the answer into a system. That person is usually the only record of why the number is what it is. When they leave, the reasoning leaves with them.

The reconciliation is the work. Reading the documents is just how you get there.

The workflow

Extract each document. Fold them after.

The order matters, and it is the reason the result is predictable. Every document is read on its own, then the results are folded by rule.

InLease, abstract, fact sheetPDF, Word, Excel, or a scan.
  1. Parse

    Read each file once, whatever it is. A scanned lease and a spreadsheet arrive as the same kind of thing downstream.

    POST /v1/files
  2. Extract

    Each document is extracted on its own, against your schema, with a citation for every field it filled.

    POST /v1/extractcitations: true
  3. Fold

    The per-document results collapse into one record by documented rules. No model decides this part, which is why it never surprises you twice.

    unit: across_documents
  4. Review

    Every contested field is listed with what each document said and which one won. Your own checks run here too.

    judge: truecitations[].confidence
  5. Send

    One record, plus what each document said on its own, into the system that tracks the portfolio.

    outputcitations[].fileId
OutOne cited recordEvery field traceable to a file, a page and a box on that page.
When they disagree

The fold keeps one answer. It also shows its work.

Three documents, three contested fields, three different rules deciding them. Nothing is averaged and nothing is blended — a value is taken whole, with its citation, from exactly one document.

  1. 01lease.pdfsent first
  2. 02lease-abstract.docx
  3. 03fact-sheet.xlsx

Monthly rent

monthly_rent
lease.pdf$12,400citedkept
lease-abstract.docx$12,000uncited
fact-sheet.xlsx$12,400uncited

Rule appliedA cited value beats an uncited one. The lease pointed at the clause it came from; the other two just asserted a number.

Rentable square feet

rentable_sqft
lease.pdfnot foundnot found
lease-abstract.docx4,820citedkept
fact-sheet.xlsx4,800uncited

Rule appliedAny real value beats an empty field. The lease never states the area, so it had nothing to contribute and was not asked to guess.

Term in months

term_months
lease.pdf60citedkept
lease-abstract.docx60cited
fact-sheet.xlsxnot foundnot found

Rule appliedBoth cited the figure just as plainly, so the tie went to the earlier file in the request. Upload order decided this one.

That last rule is worth sitting with. Reverse the two files in the request and the winner flips — this is measured behaviour, not a guess. And no wording in your instructions will change it, because instructions shape the extraction and the fold happens afterwards. Turn grounding off and every comparison becomes a tie, which makes the first file win everything.

The demo

See the merge pick a winner.

Four ways to run the same extraction, the merge behaving exactly as documented, and the review listing every field the documents fought over.

The example asks for two documents on purpose. One document leaves nothing to disagree about.Open in a new tab
Four ways in

Same record, four ways to ask for it.

The shape can come from your code, from a saved action, or from one sentence of prose. Pick per call.

An inline schema
Your JSON Schema on the request. Full control, one record per document, nullable fields so an absent term reports absence instead of a guess.
TypeScript
await sdk.extract({
  file: {id: leaseId},
  citations: true,
  schema: leaseSchema,
})
A saved action
Save the schema once under a name, reference it by slug forever. You can still ask for citations per run even if the action was saved without them.
TypeScript
await sdk.extract({
  files: [lease, abstract],
  unit: 'across_documents',
  action: 'lease-abstract',
  citations: true,
})
A sentence of hints
No schema at all. Describe what you want and the shape is inferred, then reported back on the run. For finding out what is in a document — not for production, because the field names can change between runs.
TypeScript
await sdk.extract({
  file: {id: leaseId},
  citations: true,
  hints: 'Commercial lease: rent, term, dates, renewal.',
})
How the merge behaves

Deterministic beats clever.

Most of what people expect from a document merge is wrong, and wrong in ways that cost you an afternoon. Here is what actually happens.

  • Who picks
    What people assume The model reads all the documents and picks the value it likes best.
    What happens Each document is extracted on its own. The fold that follows is ordinary code running documented rules, so the same files in the same order give the same record every time.
  • On a disagreement
    What people assume Two rents get reconciled into something in between, or the newer document wins.
    What happens Values are never blended. One value is taken whole, with its citation, from exactly one document — the best-grounded one, or the earliest in the request if they tie.
  • For list fields
    What people assume Every document contributes its rows, and you get the union.
    What happens Arrays are not unioned. A list of options or charges comes from one document, not from all of them stitched together. If you need the union, do it yourself downstream where you can see it happen.
  • Steering it
    What people assume A firmer instruction will make it prefer the signed lease.
    What happens It will not. Instructions shape the extraction; the fold happens after it. To control which document wins, control the order you send them in.
Grounding

Every value points at its source.

A citation is not a footnote. It carries the file, the page and the box on that page, so a value you are unsure about takes one click to check rather than an afternoon with a PDF.

lease.pdf1needs a lookSelect a field to see it in the document.
Page 4 of 45
Commercial Lease Agreement — 1300 Sherbrooke St W

Article 2 — Term and renewal

2.2Tenant shall have one option to renew the Term for a further five (5) years upon not less than nine (9) months written notice.
2
Commercial Lease Agreement — 1300 Sherbrooke St W

Article 4 — Rent

4

Extracted fields

TypeScript
const run = await sdk.extract({
  files: [lease, abstract, factSheet],
  unit: 'across_documents',
  citations: true,
  judge: true,          // re-score each value against the passage it cites
  schema: leaseSchema,
})

// A citation names the file, the page, and the box on that page. That is
// what the panel opposite is drawing, and what makes a value checkable.
for (const [field, cited] of Object.entries(run.output.citations)) {
  for (const c of cited) {
    console.log(field, c.fileId, c.page, c.bbox, c.confidence)
  }
}

// Confident values carry on. The rest go to a person — and the citation
// is the first thing they open.
const needsReview = Object.entries(run.output.citations)
  .filter(([, cited]) => cited.some((c) => c.confidence <= REVIEW_THRESHOLD))
  .map(([field]) => field)
For the engineers in the room

One call, however many documents.

Three steps and a decision. The merge is a field on the request, not a pipeline you assemble.

  1. 01

    Register the documents, in order

    One file record per document, then PUT the bytes to each upload URL. Keep the order deliberate — request order is what breaks ties in the fold, so the document you trust most goes first.

    POST /v1/filesGET /v1/files/:id
  2. 02

    Ask for one record instead of several

    Send a files array rather than a single file, set unit to across_documents, and leave citations on. Grounding is what lets the fold rank two competing values instead of falling back to order alone.

    POST /v1/extractunit: across_documentscitations: true
  3. 03

    Add the second opinion

    Set judge to true and a second pass re-scores each value against the passage it cites. It needs citations on to have anything to read. Low scores are your queue for a person, not a reason to discard the value.

    judge: truecitations[].confidence
  4. 04

    Read the record and the receipts

    You get the merged record, and every citation carries the fileId it came from — which is what makes the merge auditable rather than merely convenient. Keep the run and it becomes a permanent record instead of expiring with its default TTL.

    citations[].fileIdcitations[].pagePOST /v1/runs/:id/keep
After the record

An abstract is not the end of the job.

Once the terms are structured, the documents that quote them can be produced rather than typed.

Write the abstract
The abstract that disagreed with the lease was typed by hand. Generate the next one from the record instead, and it cannot drift.
See Compose
Fill the estoppel
Estoppel certificates, SNDAs, tenant questionnaires. The boxes they want are the fields you already extracted.
See Fill
Redact before it circulates
Leases carry rents and names that a lender or a broker has no business reading. Strip them out for good, not with a black rectangle.
See Redact
Send it for signature
The amendment you generated needs signing. Same run, no new vendor.
See Sign
Cut the packet up first
Sometimes all four documents arrive as one scanned PDF. Classify finds the boundaries and Split makes them addressable files.
See Split
Do it to the whole portfolio
A lease at a time is a demo. Batch is how a thousand leases become a dataset — save the schema as an action first, because batch will not take hints.
Run it yourself

This page is a program you can clone.

Everything above ships as a runnable TypeScript example under MIT, with sample documents included. Bun install, drop in an API key, run it. All four ways to call the extraction are selectable in the UI, and the review screen is the one in the video.

The interesting experiment takes ten seconds: reverse the two documents in the file list and watch the tied field change its answer. That is the whole argument for deterministic rules over a model that quietly picks a favourite.

github.com/CloudRaker/cloudraker-api-examples-typescript — the rental-lease-extraction folder.

Capabilities used

The building blocks under this one.

One capability and three of its settings carry this whole workflow.

Parse
PDF, Word, Excel, or a scan of any of them. Each file is read once and shared by every step that follows.
Parse docs
Extract
Your JSON Schema, a saved action, or one sentence of hints. Nullable fields let a missing clause report absence rather than a guess.
Extract docs
Grounding
Every filled field carries a citation with the file, the page and the box on that page. It is also what lets the fold rank two competing answers.
Citations docs
Judge
A second pass that re-scores each value against the passage it cites. Needs grounding on. Confident values carry on; the rest go to a person, and you set where that line sits.
Confidence docs
Start here

Your documents already disagree. Now you can see where.

Take two leases you already argue about, send them in one call, and read the disagreement list. Ten minutes, and you will know whether this belongs in your stack.