[ Property ]

Rent rolls and leases, built on extraction you can trust

Sensible is the extraction layer under your property underwriting workflow: schema-validated and traceable to the source page, so your deal team can trust the data without checking it by hand.

14-day free trial · No credit card
Source document
Harborview Residences
RENT ROLL
RR-2024-0331
Property
1420 Marine Way
Marlow Bay, WA 98122
As of
03/31/2024
Prepared
04/01/2024
Units
101 – 301
Page
1 of 2
Unit · endsMonthlyAnnual
101 · 03/31/20252,150.0025,800.00
102 · 11/30/20242,095.0025,140.00
201 · 06/30/20252,875.0034,500.00
202 · 01/31/20252,940.0035,280.00
301 · 09/30/20243,010.0036,120.00
Page total, monthly
$13,070.00
Page total, annual
$156,840.00
POST
/v0/extract/rent_roll
200 OK
{
"parsed_document": {
"property_name": {
"value": "Harborview Residences",
"type": "string"
},
"report_number": {
"value": "RR-2024-0331",
"type": "string"
},
"property_address": {
"value": "1420 Marine Way",
"type": "string"
},
"as_of_date": {
"source": "03/31/2024",
"value": "2024-03-31T00:00:00.000Z",
"type": "date"
},
"prepared_date": {
"source": "04/01/2024",
"value": "2024-04-01T00:00:00.000Z",
"type": "date"
},
"unit_range": {
"value": "101 – 301",
"type": "string"
},
"report_page": {
"value": "1 of 2",
"type": "string"
},
"units": [
{
"unit": "101",
"lease_end": "2025-03-31",
"monthly_rent": 2150,
"annual_rent": 25800
},
{
"unit": "102",
"lease_end": "2024-11-30",
"monthly_rent": 2095,
"annual_rent": 25140
},
// + 3 more rows
],
"total_monthly_rent": {
"source": "$13,070.00",
"value": 13070,
"unit": "$",
"type": "currency"
},
"total_annual_rent": {
"source": "$156,840.00",
"value": 156840,
"unit": "$",
"type": "currency"
}
},
"validations": {
"rent_roll_totals": "pass",
"monthly_rollup": "pass",
"lease_math": "pass",
"lease_end_after_as_of": "pass"
}
}
10 fields
values can carry their page + polygon
Source document
Harborview Residences
RESIDENTIAL LEASE
01/12/2024
Premises
1420 Marine Way, Unit 202
Marlow Bay, WA 98122
Tenant
Naomi Delgado
Term
Twelve (12) months
Starts
02/01/2024
Ends
01/31/2025
Move-in chargeDueAmount
First month's rent02/01/20242,940.00
Security deposit01/12/20242,940.00
Late fee (5%)
$147.00
Total move-in costs
$5,880.00
POST
/v0/extract/lease
200 OK
{
"parsed_document": {
"property_name": {
"value": "Harborview Residences",
"type": "string"
},
"lease_date": {
"source": "01/12/2024",
"value": "2024-01-12T00:00:00.000Z",
"type": "date"
},
"premises_address": {
"value": "1420 Marine Way, Unit 202",
"type": "string"
},
"tenant_name": {
"value": "Naomi Delgado",
"type": "string"
},
"lease_term_months": {
"source": "Twelve (12) months",
"value": 12,
"type": "number"
},
"lease_start": {
"source": "02/01/2024",
"value": "2024-02-01T00:00:00.000Z",
"type": "date"
},
"lease_end": {
"source": "01/31/2025",
"value": "2025-01-31T00:00:00.000Z",
"type": "date"
},
"move_in_charges": [
{
"description": "First month's rent",
"due": "02/01/2024",
"amount": 2940
},
{
"description": "Security deposit",
"due": "01/12/2024",
"amount": 2940
}
],
"late_fee_amount": {
"source": "$147.00",
"value": 147,
"unit": "$",
"type": "currency"
},
"total_move_in_costs": {
"source": "$5,880.00",
"value": 5880,
"unit": "$",
"type": "currency"
}
},
"validations": {
"term_matches_dates": "pass",
"late_fee_math": "pass",
"move_in_rollup": "pass"
}
}
10 fields
values can carry their page + polygon
Source document
Cascade Ridge Mortgage
CLOSING DISCLOSURE
LN-4471902
Property
1420 Marine Way, Unit 202
Marlow Bay, WA 98122
Closing date
05/10/2024
Sale price
$462,000.00
Loan amount
$346,500.00
Interest rate
6.875%, fixed
Loan costsSectionAmount
Origination chargesA4,660.00
Services not shopped forB707.00
Services shopped forC1,845.00
Total other costsI5,519.05
Total loan costs
$7,212.00
Total closing costs
$12,731.05
POST
/v0/extract/closing_disclosure
200 OK
{
"parsed_document": {
"lender_name": {
"value": "Cascade Ridge Mortgage",
"type": "string"
},
"loan_id": {
"value": "LN-4471902",
"type": "string"
},
"closing_date": {
"source": "05/10/2024",
"value": "2024-05-10T00:00:00.000Z",
"type": "date"
},
"property_address": {
"value": "1420 Marine Way, Unit 202",
"type": "string"
},
"sale_price": {
"source": "$462,000.00",
"value": 462000,
"unit": "$",
"type": "currency"
},
"loan_amount": {
"source": "$346,500.00",
"value": 346500,
"unit": "$",
"type": "currency"
},
"interest_rate": {
"source": "6.875%, fixed",
"value": 6.875,
"type": "number"
},
"closing_costs": [
{
"section": "A",
"description": "Origination charges",
"amount": 4660
},
{
"section": "B",
"description": "Services not shopped for",
"amount": 707
},
// + 2 more rows
],
"total_loan_costs": {
"source": "$7,212.00",
"value": 7212,
"unit": "$",
"type": "currency"
},
"total_closing_costs": {
"source": "$12,731.05",
"value": 12731.05,
"unit": "$",
"type": "currency"
}
},
"validations": {
"loan_cost_rollup": "pass",
"closing_cost_rollup": "pass",
"loan_below_price": "pass"
}
}
10 fields
values can carry their page + polygon

Hover a field to trace it to the source. Sample data; output is illustrative.

Per field

LLM or deterministic method

Per document

pricing, whatever the page count

SOC 2 + HIPAA

SOC 2 Type II · BAA on Enterprise

No credit card

14-day free trial

Trusted by teams turning documents into production data

Why property extraction is hard

Each system exports a rent roll its own way. Your model needs one format.

  • The same column is Monthly, Scheduled or Contract rent by system
  • Unit IDs like PH1 and 0202 read as numbers in some rows
  • Rents and dates print as text, and underwriting needs typed values
  • Totals sit above or below the table and shift between exports
Export chaos
One schema
Why property extraction is hard in production

Where rent roll extraction breaks in production

Units, rents and lease dates land somewhere different in each system’s export. You choose the extraction method for each field, and each value comes back typed and traced to its page.

01

Layout diversity by system

Property-management exports and lender packets name the same column Monthly, Scheduled rent or Contract rent, and put totals above or below the table. Layout methods take the fixed columns and an LLM method reads the rest.

02

Unit IDs, dates and amounts

Unit PH1 is a string, 0202 is easy to coerce to a number, and the lease end 01/31/2025 has to become a date. Units stay strings, dates become ISO 8601 and amounts become currency, with the printed text kept as source.

03

Rent arithmetic validation

Do the units add up to the total? Does rent times 12 equal annual rent? If the annual total reads 156,480.00 where the units sum to 156,840.00, the 360.00 gap comes back as a validation error and the roll can be held for review.

04Property-specific

Unit and address match readiness

A unit on the rent roll has to match the lease and the closing disclosure that name it. Sensible returns the unit and address clean, down to PH1 and 0202, so your underwriting platform can match the three.

What Sensible extracts

The fields we extract

Grouped the way underwriters ask for them. Each field comes back typed, keeps the text as printed, and can point to where it sits on the page.

Field
Schema key
How Sensible handles it
Validated in
Property name
property_namestring
As printed from the report title.
Property address
property_addressstring
As printed, street through postal code.
As-of date
as_of_datedate
ISO 8601 value, with the printed text kept as source.
Lease end
Prepared date
prepared_datedate
ISO 8601 value, printed text kept.
Management company
management_companystring
When printed.
Property ID
property_idstring
When printed, kept as printed.
Report number
report_numberstring
As printed, including leading zeros.
Report page
report_pagestring
Kept as printed, such as 1 of 2.
Unit range
unit_rangestring
The first and last unit the page covers.
Field
Schema key
How Sensible handles it
Validated in
Unit
unitstring
A string, so PH1 and 0202 survive.
Unit type
unit_typestring
1BR, 2BR, PH and the like, as printed.
Lease end
lease_enddate
ISO 8601 value, printed text kept.
Lease end
Square feet
sq_ftnumber
Parsed to a number, thousands separators handled.
Monthly rent
monthly_rentcurrency
A number, with the printed text kept as source.
Rent × 12
Annual rent
annual_rentcurrency
A number, with the printed text kept as source.
Rent × 12
Tenant name
tenant_namestring
When printed. Vacant units come back as vacant.
Lease start
lease_startdate
When printed.
Field
Schema key
How Sensible handles it
Validated in
Total square feet
total_sq_ftnumber
Checked against the sum of the unit rows.
Total monthly rent
total_monthly_rentcurrency
Checked against the sum of the monthly rents.
Monthly
Total annual rent
total_annual_rentcurrency
Checked against the sum of the annual rents.
Annual
Total units
total_unitsnumber
Checked against the count of unit rows.
Occupied units
occupied_unitsnumber
When printed.
Vacant units
vacant_unitsnumber
When printed.
Occupancy
occupancy_ratenumber
When printed, stored as a decimal with the text kept.
Total market rent
total_market_rentcurrency
When printed, for loss-to-lease work.
Your schema, not a fixed list.
Each deal team’s schema is different, so this is a starting point mapped to yours. Often added: market rent, loss to lease, concessions, security deposits held, charge codes, arrears.
How it works

How a rent roll moves through Sensible

Five stages, and values can carry the page and polygon they came from all the way through.

01

Ingest

PDF, scan, spreadsheet export or email attachment. Any source, no pre-sorting.

in files, email, API
out normalized pages
02

Classify

Document type identified (rent roll, lease, closing disclosure, inspection report) before extraction runs.

in normalized pages
out typed document
03

Extract

You pick the method for each field: an LLM where layouts vary, a layout or anchor method where the position holds.

in typed document
out candidate fields
04

Validate

Calculation checks run on the output: unit rents to totals, monthly rent times 12 to annual rent. Failures are flagged for review.

in candidate fields
out checked fields + flags
05

Deliver

Typed JSON, with page and polygon per value when verbosity is set, sent by webhook or pulled by API.

in checked fields
out JSON to your system
Sensible: the extraction layer
Then

Webhook or API into your underwriting platform or loan origination system. NOI and debt service calculations happen there. Sensible hands over data you can load; it doesn’t run those steps.

Where the value came from
total_annual_rent → page 1
polygon 4 points, in inches
source "$156,840.00"
Validation, not just extraction

How the rent numbers get checked

Getting a rent off a PDF is the easy part. The question your underwriting team asks is whether it’s the right rent, so Sensible checks each rent roll the way an analyst would. When a check fails, the field is flagged and can be routed for review instead of flowing into your model.

Validation results
RR-2024-0331
✓
Annual rents sum to total
5 units add up to the stated annual total
$156,840.00
✓
Monthly rents sum to total
5 units add up to the stated monthly total
$13,070.00
✓
Rent times 12 equals annual
Checked on each of the 5 units; unit 101 shown
25,800.00
✓
Leases end after as-of date
All 5 lease ends fall after the as-of date
03/31/2024
!
A check that fails
Units sum to $156,840.00 but the annual total reads $156,480.00, so the field is flagged and sent to review
review
Our position

We don’t publish a flat accuracy percentage. Accuracy depends on document quality and configuration, and a single number hides both.

Sensible
Self-serve or managed

Don’t want to build property configurations yourself? Our team can write and maintain the configs for you.

Solutions engineers write the SenseML configs from your samples, adjust them when formats change, and help with integration work. You get the same engine as self-serve, with the configuration work done for you.

01

Plan

Engineers review your samples and pick the right method.

02

Build

SenseML configs written from your samples.

03

Deploy

Same engine as self-serve, ready for production.

04

Adjust

Configs updated when formats shift or new edge cases appear.

05

Integrate

Help with custom integration into your downstream systems.

Supported formats

Exports, leases and lender documents

The extraction logic is written out in SenseML rather than buried in prompts, so a new format can be added and reviewed.

By source

Property-management exports · Owner and asset-manager reports · Lender and servicer packets · Title and escrow documents · Offering packages · Spreadsheet rent rolls

Leases and contracts

Term, rent, deposit, escalations and options, read from the clause wherever it sits.

Inspection reports

Findings, severity ratings and cost items. Inspect-It 1st uses Sensible for these.

Loan packets

Multi-document packets are split and classified before extraction against your schema.

File formats

PDF (native or scanned) · Excel and CSV exports · Word (DOC / DOCX) · JPEG / PNG · TIFF · Email bodies and attachments

Common questions

Questions from property teams

Scope, system formats, checks, leases, and where Sensible stops and your underwriting stack starts.

Does Sensible underwrite a property or calculate NOI itself?+

No. Sensible is the extraction layer. It reads the rent roll, the lease and the closing disclosure, and captures the fields that feed underwriting (unit, rent, lease dates, loan terms) in a consistent, schema-validated shape. The underwriting logic itself, including NOI and debt service, lives downstream in your own models or underwriting platform.

Can Sensible confirm that a lease matches the rent roll?+

Not as a built-in feature. Sensible’s validation rules run against one document at a time, and comparing a lease to the rent roll row it belongs to needs two documents.

What Sensible does give you is clean fields on each: unit, address, monthly rent and lease dates, extracted the same way each time. Comparing them belongs in your underwriting platform or your own models. If you want that wired in as part of the pipeline, our managed-services team can help with the integration.

Is pricing per document for high-volume property teams?+

Sensible prices per document, not per token, so cost is predictable at 500 documents a month or 50,000. One extraction result counts as one document, whatever its page count. A packet that Sensible splits into several documents counts each one. Enterprise plans add volume tiers; see pricing or talk to our team for a volume quote.

Does Sensible catch bad extractions before they reach your model?+

Computed checks confirm that unit rents sum to the total, that monthly rent times 12 equals annual rent, and that lease ends fall after the as-of date. A failed check is flagged and can be routed to human review. Results come back by webhook or API, or as Excel or CSV.

How accurate is the extraction?+

Accuracy depends on document quality and configuration, so we don’t quote a single flat number. What we can tell you is how the output is checked: schema enforcement and calculation validation, so weak extractions are flagged instead of passed through silently. The best way to know is to run your own rent rolls, including the worst exports, through it.

How is property data secured, and how long is it retained?+

Sensible holds a SOC 2 Type II report from an independent audit, and data is encrypted in transit and at rest. HIPAA is available on Enterprise with a signed BAA. Custom data retention is also on Enterprise, so talk to our team about the retention you need.

Try Sensible on your documents.

Send the export from your oldest system. If it works on that one, you’ll know.

14-day free trial on any paid plan · No credit card