Abstract commercial leases and extract structured data via REST API
Get your API key from the API keys page and start abstracting leases!
curl -X POST 'https://leasebossai.com/api/parse.php' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{ "file": "https://example.com/lease.pdf" }'
https://leasebossai.com/api
For production: https://leasebossai.com/api
All API requests require an API key in the Bearer authorization header:
Authorization: Bearer YOUR_API_KEY
Do not put an API key in a URL. Query-string keys are rejected because URLs are routinely saved in browser history, access logs, analytics and referrer headers.
The API supports cross-origin requests for integrations, including the
Authorization header. A Bearer key grants its holder access without
another login, so keep it in a server-side secret store. Do not embed it in public
browser JavaScript, local storage, a mobile binary or a client-side repository.
Abstract a lease document and extract structured data.
/api/parse.php
Cost: $20 per lease contract.
An amendment to a lease already on your account is free, and a document that
fails to abstract is not charged. The usage block in the response
says which of those happened.
curl -X POST https://leasebossai.com/api/parse.php \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "file=@/path/to/lease.pdf"
curl -X POST https://leasebossai.com/api/parse.php \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "file": "https://example.com/lease.pdf" }'
Maximum File Size: 10 MB
Scans and photographs are read with OCR. Where the read is poor — blank
pages, low confidence, pages that had to be rotated, or a footer claiming more
pages than were uploaded — the abstraction carries
ocr_* findings
saying so, rather than quietly returning a short abstract.
A ZIP archive of leases can be uploaded on the batch page. It is expanded on the server and each document inside becomes its own job; folder structure is discarded and anything unreadable is reported rather than failing the batch.
Note: This API is designed to abstract one lease per request. If a file contains multiple leases, unexpected results may occur.
Everything above abstracts a document. Everything here reads what has already been abstracted — leases, abstracts, clauses, schedules, key dates, findings and search — under a versioned path, with the same API key.
curl https://leasebossai.com/api/v1/leases?per_page=10 \ -H "Authorization: Bearer YOUR_API_KEY"
page, per_page (max 100); follow next/parse is charged.| Method | Path | Returns |
|---|---|---|
| GET |
/v1
|
This list of endpoints |
| GET |
/v1/leases
|
The organization's leases, newest first
|
| GET |
/v1/leases/{id}
|
One lease: consolidated fields and provenance |
| GET |
/v1/leases/{id}/abstract
|
The lease abstract |
| GET |
/v1/leases/{id}/clauses
|
Segmented and classified provisions
|
| GET |
/v1/leases/{id}/payments
|
The payment schedule |
| GET |
/v1/leases/{id}/amendments
|
Amendments attached to this lease |
| GET |
/v1/leases/{id}/validations
|
Risk findings for this lease
|
| GET |
/v1/leases/{id}/text
|
The converted document text |
| GET |
/v1/events
|
Key dates across the portfolio
|
| GET |
/v1/payments
|
Upcoming payments across the portfolio |
| GET |
/v1/validations
|
Risk findings across the portfolio
|
| GET |
/v1/search
|
Hybrid keyword, semantic and facet search
|
| GET |
/v1/portfolio
|
Portfolio statistics |
| GET |
/v1/analytics
|
WALT, expiration ladder and concentration, with coverage
|
| GET |
/v1/entities
|
Properties, tenants and landlords
|
| GET |
/v1/entities/{id}
|
One property, tenant or landlord |
| GET |
/v1/entities/{id}/leases
|
The leases filed under it |
| GET |
/v1/portfolios
|
Named groupings of properties |
| GET |
/v1/batches
|
Recent upload batches |
| GET |
/v1/batches/{id}
|
One batch and its files |
| GET |
/v1/webhooks
|
Configured webhook endpoints |
| GET |
/v1/webhooks/deliveries
|
Recent webhook delivery attempts
|
| POST |
/v1/chat
|
Ask a question, answered with citations
|
| POST |
/v1/parse
|
Abstract one lease document
|
Three shapes and no others. Every response carries
success and a
request_id,
which is also returned in the X-Request-Id
header — quote it if you need to ask us about a request.
// one resource { "success": true, "request_id": "...", "data": { ... } } // a page of a collection. count is the whole collection, not this page. { "success": true, "request_id": "...", "count": 41, "page": 1, "per_page": 25, "next": "https://leasebossai.com/api/v1/leases?page=2", "previous": null, "results": [ ... ] } // an error. error_code is the stable value to branch on. { "success": false, "request_id": "...", "error": "No lease with id 41.", "error_code": "not_found" }
A lease carries its tenant, landlord and address as text, the way the
document wrote them. That is enough to display and useless to count:
the same tenant arrives as
Coastal Robotics, Inc.
on one lease and
COASTAL ROBOTICS INC
on the next, and two suites of one building look like two buildings.
/v1/entities
is the resolved version: one record per tenant, landlord and building,
with the leases filed under it.
The identity two names have to share to be treated as one. Every
entity publishes its own, so you can tell why two leases were
grouped — or why they were not — without asking us,
and reproduce the same grouping over your own data. Legal
suffixes, punctuation and case are removed; for a building the
suite is dropped and the street type abbreviated, so
400 Harbor Way, Suite 200, Boston, MA
becomes 400 harbor way|boston|ma.
Grouping is deliberately cautious: one word different is a
different company until somebody says otherwise. When they do,
the record they merged away is kept and points at the survivor,
so an id you stored keeps working. Follow
merged_into when it is not null
rather than treating the record as current.
/v1/analytics
returns the four figures a portfolio gets judged by, computed from those
records: WALT (weighted average lease term, in years),
the expiration ladder, concentration
by tenant, landlord and building, and rent per building.
A weighted average over the two thirds of a portfolio that had a
readable expiration date is not an approximate answer — it is
an answer about a different portfolio. So every figure arrives with
the count behind it and what it had to leave out:
walt.counted,
walt.excluded.no_expiration_date,
walt.excluded.expired, and a
coverage block for the whole payload.
Concentration reports
unattributed for leases whose party we
could not identify, and it is in the denominator — so the
shares are of the real portfolio rather than of the part we
understood.
WALT comes back three ways:
by_rent,
by_rentable_sf
and unweighted,
because when the first two disagree that is the finding: a
rent-weighted term well above the area-weighted one means the expensive
space is what runs longest, and the near-term expiries are the cheap
space.
Concentration includes an HHI — the
Herfindahl–Hirschman index, the sum of each group's squared
percentage share, from near 0 to 10,000. It is reported over every
group, not just the ones named in results,
so narrowing top does not change it. The
accompanying hhi_label reads it against the
usual thresholds (1,500 and 2,500) so you do not have to pick your own.
curl https://leasebossai.com/api/v1/analytics?years=10&top=5 \ -H "Authorization: Bearer YOUR_API_KEY" { "success": true, "data": { "walt": { "by_rent": 5.9, "by_rentable_sf": 5.6, "unweighted": 6.4, "unit": "years", "counted": 3, "excluded": { "no_expiration_date": 1, "expired": 1, ... } }, "expiration_ladder": { "years": [ { "year": 2026, "lease_count": 0, "annual_rent": 0.0, "share_of_rent": 0.0 }, ... ], "expired": { ... }, "undated": { ... }, "peak_year": 2029 }, "concentration": { "tenant": { "groups": 3, "hhi": 3841.2, "hhi_label": "Highly concentrated", "top_share": 0.438, "results": [ ... ], "unattributed": { "lease_count": 0, "annual_rent": null } }, "landlord": { ... }, "property": { ... } }, "coverage": { "live_lease_count": 3, "with_expiry": 3, "with_tenant": 3, ... } } }
Rather than polling /leases
to see whether an upload finished, subscribe an endpoint on the
Webhooks
page and we will post to it. Delivery is retried
6 times with a widening gap, so a
deploy or a restart on your side does not lose an event.
| Event | Sent when |
|---|---|
lease.parsed |
A document finished extraction and was saved, however it arrived: dashboard, API or batch. |
lease.updated |
A person corrected a field, or an amendment was attached or detached, so the position in force is different from before. |
batch.completed |
Every file in an upload batch reached a final state. |
validation.opened |
A check began failing on a lease that was previously clean, or a new document raised one. |
key_date.due |
A dated obligation crossed 90, 30 or 7 days out, or passed. Sent once per date per threshold, not daily. |
ping |
Sent only when you ask for one, to prove the endpoint works before it matters. |
A thin payload and a link, not the whole extraction. The lease object is
the same one GET /v1/leases
returns, so nothing you learn here can disagree with what you fetch next.
POST /your/endpoint
Content-Type: application/json
X-LeaseBoss-Event: lease.parsed
X-LeaseBoss-Delivery: evt_9f86d081884c7d65
X-LeaseBoss-Signature: t=1767225600,v1=5257a869e7ecdb4d...
X-LeaseBoss-Attempt: 1
{
"id": "evt_9f86d081884c7d65",
"event": "lease.parsed",
"created_at": "2026-01-01T09:20:00+00:00",
"data": {
"lease": { "id": 41, "tenant_name": "Coastal Robotics Inc",
"property_address": "400 Harbor Way", "monthly_rent": 12500.00,
"expiration_date": "2029-06-30",
"links": { "self": "https://leasebossai.com/api/v1/leases/41" } },
"source": "api",
"counts": { "clauses": 42, "open_risks": 3, "fields_to_review": 7, "pages": 31 },
"amendment": null
}
}
Anyone who learns your URL can post to it, so check the signature before
you trust the body. The HMAC is taken over
<t>.<raw body>
with SHA-256 and your signing secret. Check t
too — without a freshness window, a delivery captured once can be
replayed forever.
# Python import hashlib, hmac, time def verify(header, body, secret, tolerance=300): parts = dict(p.split("=", 1) for p in header.split(",")) t = int(parts["t"]) if abs(time.time() - t) > tolerance: return False expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts["v1"])
Reply 2xx as soon as you have the payload and do the work behind your own queue. We wait 10 seconds, and anything else is treated as a failure and retried.
A retry carries the same X-LeaseBoss-Delivery
id. Treat it as the idempotency key: a network failure after your
200 means we will send it again.
Private and internal addresses are refused. The signature proves who sent a payload, not that nobody else read it.
Every attempt and what your endpoint said is on the Webhooks page,
and at GET /v1/webhooks/deliveries.
After 20 consecutive
failures we stop calling and tell you.
Every response carries four blocks under data:
document (what kind of document this is),
parsed (the extracted terms, always the
full schema whether or not a value was found),
provenance (the quote behind each value,
keyed by dotted field path), and
meta (file and run details).
Absent values are present as fields. A term the lease does not
address comes back as null,
"" or []
rather than being omitted, so you can tell “the lease is silent” from
“we did not look”. Fields with no
provenance entry were not found in the document.
{
"success": true,
"abstraction_id": 1842,
"data": {
"document": {
"document_type": "lease",
"amendment_number": null,
"amendment_type": "",
"effective_date": "",
"amends_lease_dated": "",
"amends_property": "",
"amends_tenant": ""
},
"parsed": {
"basic_info": {
"lease_type": "Triple Net (NNN)",
"execution_date": "2024-01-15",
"governing_state": "WA"
},
"parties": {
"landlord_name": "Harbor Point Owner LLC",
"landlord_address": "1200 Harbor Point Drive, Suite 900, Seattle, WA 98101",
"tenant_name": "Northwind Analytics Inc.",
"tenant_address": "1200 Harbor Point Drive, Suite 400, Seattle, WA 98101",
"guarantor_name": "Northwind Holdings Inc.",
"guarantor_address": "",
"property_manager_name": "Cascade Commercial Management",
"property_manager_contact": "jrivera@cascadecm.example (206) 555-0142"
},
"premises": {
"property_name": "Harbor Point Tower",
"property_address": "1200 Harbor Point Drive, Seattle, WA 98101",
"premises_description": "Suite 400 on the fourth floor, as shown on Exhibit A",
"suite_unit": "400",
"floor": "4",
"county": "King",
"property_type": "Office",
"rentable_sf": 12000,
"usable_sf": 10800,
"parking_spaces": 24
},
"lease_term": {
"commencement_date": "2024-03-01",
"rent_commencement_date": "2024-06-01",
"possession_date": "2024-02-15",
"expiration_date": "2029-02-28",
"initial_term_months": 60,
"free_rent_months": 3,
"holdover_rate": 150
},
"term_certainty": {
"commencement_status": "",
"expiration_status": "",
"area_status": "",
"basis": "",
"trigger_event": "",
"outside_date": "",
"confirming_document": ""
},
"base_rent": {
"initial_monthly_rent": 30000,
"initial_annual_rent": 360000,
"rent_per_sf": 30,
"amount_kind": "",
"amount_text": "",
"currency": "USD",
"payment_frequency": "monthly",
"escalation_type": "fixed_percent",
"annual_escalation_percent": 3,
"cpi_index_name": "",
"cpi_floor_percent": null,
"cpi_ceiling_percent": null,
"percentage_rent_rate": null,
"breakpoint_sales_amount": null,
"rent_review_date": "",
"review_assumptions": "",
"rent_schedule": [
{
"year": 1,
"monthly_rent": 30000,
"annual_rent": 360000,
"rent_psf": 30
},
{
"year": 2,
"monthly_rent": 30900,
"annual_rent": 370800,
"rent_psf": 30.9
}
]
},
"operating_expenses": {
"expense_type": "Triple Net (NNN)",
"base_year": "2024",
"pro_rata_share": 12.5,
"expense_stop_psf": null,
"estimated_opex_psf": 11.5,
"estimated_annual_opex": 138000,
"cam_cap_percent": 5,
"cam_cap_basis": "non_cumulative",
"cam_exclusions": [
"Capital improvements except as amortized",
"Leasing commissions and marketing costs"
],
"admin_fee_percent": 3,
"property_tax_responsibility": "tenant",
"insurance_responsibility": "tenant",
"audit_right_days": 90
},
"security": {
"security_deposit": 60000,
"security_deposit_form": "cash",
"loc_amount": null
},
"renewal_options": {
"renewal_option_count": 2,
"renewal_term_months": 60,
"renewal_notice_days": 270,
"renewal_rent_basis": "Fair market rent, not less than the then-current rent"
},
"termination": {
"early_termination_allowed": true,
"termination_effective_date": "",
"termination_notice_days": 270,
"termination_fee": 180000
},
"tenant_improvements": {
"ti_allowance_total": 600000,
"ti_allowance_psf": 50,
"restoration_required": false,
"return_conditions": "Broom clean, ordinary wear and tear excepted",
"end_of_term_obligations": ""
},
"use_and_operations": {
"permitted_use": "General office and software development",
"exclusive_use": "None"
},
"assignment_subletting": {
"assignment_allowed": "With Landlord's prior written consent, not to be unreasonably withheld",
"subletting_allowed": "With Landlord's prior written consent for up to 40% of the Premises"
},
"construction_completion": {
"tenant_improvement_work": "",
"landlord_work": "",
"completion_deadline": "",
"permits_responsibility": "",
"construction_insurance_required": false
},
"utilities": {
"tenant_responsible_for": [
"Electricity",
"Telecommunications",
"Janitorial"
],
"landlord_responsible_for": [
"Water",
"Sewer",
"Common area electricity"
],
"utility_notes": ""
},
"maintenance_repairs": {
"landlord_responsible": [],
"tenant_responsible": [],
"hvac_responsibility": "",
"roof_structure_responsibility": "",
"common_area_maintenance": ""
},
"maintenance_matrix": {
"roof": "landlord",
"hvac": "tenant",
"parking_lot": "landlord",
"foundation_structure": "landlord",
"plumbing": "tenant",
"electrical": "tenant",
"windows_glass": "tenant",
"exterior": "landlord",
"interior": "tenant",
"landscaping": "landlord",
"pest_control": "",
"janitorial": "tenant",
"elevator": "landlord",
"fire_life_safety": "shared",
"snow_removal": "landlord"
},
"insurance_requirements": {
"general_liability_limit": 2000000,
"property_insurance_required": true,
"workers_comp_required": true,
"landlord_as_additional_insured": true,
"insurance_notes": ""
},
"default_remedies": {
"monetary_default_cure_days": 5,
"non_monetary_default_cure_days": 30,
"late_fee_percent": 5,
"late_fee_fixed_amount": null,
"interest_rate_on_late_payments": 12,
"landlord_remedies": "",
"tenant_remedies": ""
},
"warranties": {
"landlord_warranties": "",
"tenant_warranties": "",
"warranty_notes": ""
},
"legal_provisions": {
"estoppel_required": "yes",
"estoppel_response_days": 10,
"snda_required": "yes",
"subordination_automatic": "yes",
"force_majeure_present": "yes",
"force_majeure_summary": "",
"holdover_consent_required": "yes",
"holdover_summary": "",
"guaranty_present": "yes",
"guaranty_type": "Limited corporate guaranty",
"guaranty_capped_amount": 720000,
"guaranty_summary": "",
"attorneys_fees_prevailing_party": "yes",
"jury_trial_waiver": "yes",
"relocation_right": "no",
"right_of_first_refusal": "no",
"right_of_first_offer": "yes",
"purchase_option": "no",
"purchase_option_summary": "",
"co_tenancy_clause": "no",
"casualty_restoration_days": 180,
"casualty_summary": "",
"condemnation_summary": "",
"environmental_provisions": "",
"dispute_resolution": "Binding arbitration in King County, Washington",
"notice_method": "Certified mail or nationally recognised overnight courier"
},
"additional_provisions": [
"Tenant holds a right of first offer on the 5th floor.",
"Landlord to deliver the Premises with a new roof membrane."
]
},
"provenance": {
"base_rent.initial_monthly_rent": {
"snippet": "Base Rent shall be Thirty Thousand Dollars ($30,000.00) per month",
"page": 4,
"basis": "verbatim",
"confidence": 0.96
},
"base_rent.initial_annual_rent": {
"snippet": "Base Rent shall be Thirty Thousand Dollars ($30,000.00) per month",
"page": 4,
"basis": "derived",
"confidence": 0.96
},
"lease_term.expiration_date": {
"snippet": "the Term shall expire on February 28, 2029",
"page": 3,
"basis": "verbatim",
"confidence": 0.94
},
"maintenance_matrix.roof": {
"snippet": "Landlord shall maintain, repair and replace the roof",
"page": 11,
"basis": "verbatim",
"confidence": 0.91
},
"premises.rentable_sf": {
"snippet": "containing approximately 12,000 rentable square feet",
"page": 2,
"basis": "verbatim",
"confidence": 0.93
}
},
"meta": {
"filename": "harbor_point_suite_400.pdf",
"file_type": "pdf",
"file_size": 482913,
"file_hash": "d41d8cd98f00b204e9800998ecf8427e",
"status": "success",
"processing_time": 8.41,
"error_message": null,
"cost": 20,
"balance_before": 0,
"balance_after": 0,
"source": "api",
"has_provenance": true,
"page_count": 42
}
},
"usage": {
"cost": 20,
"billed": true,
"billing_reason": "lease_contract",
"credit_applied": 0,
"balance_remaining": 0,
"calls_made": 137
},
"validation": {
"open": 2,
"by_level": {
"error": 0,
"warning": 2,
"info": 0
},
"findings": [
{
"code": "critical_fields_unverified",
"level": "warning",
"title": "Critical values are unverified",
"field_path": null,
"message": "6 critical values have not been verified: Commencement Date, Annual Escalation Percent, Tenant Name and 3 others."
},
{
"code": "missing_exhibit",
"level": "warning",
"title": "Referenced exhibits are not in the document",
"field_path": null,
"message": "The lease refers to Exhibit A, which does not appear in the document."
}
]
}
}
Generated from the live extraction schema, so this example always matches the
current response shape. Two blocks are conditional and not shown above:
duplicate_of, an abstraction
ID present when the same file is already in your portfolio, and
amendment, present when the
document amends an existing lease rather than being one.
Every value the model fills in is returned with the text that supports it, keyed by
the same dotted path used in parsed.
An abstraction you cannot trace back to the lease is a guess, so
provenance is how you decide
what to accept automatically and what to route to a person.
| Key | Meaning |
|---|---|
snippet |
The passage the value came from, quoted from the document. |
page |
Page the passage was found on, or null when the document carries no page markers. |
basis |
verbatim — the value appears in the text as written.
derived — calculated from other values, such as annual rent from monthly.
inferred — read from context rather than stated.
human — corrected or confirmed by a reviewer, which outranks everything above.
|
confidence |
0–1. Below 0.6 the value is queued for review in the app, as is any value that cited nothing at all; a human basis is always treated as verified. |
Every field in parsed,
with its dotted path. Priority is how much a wrong or missing value
matters: critical fields drive the review queue and the risk checks.
Enum fields accept only the listed values — an empty string
means the lease does not address the point, which is deliberately distinct from a
value of “landlord” or “no”.
155 fields across 22 sections.
basic_info
| Path | Type | Priority | Allowed values |
|---|---|---|---|
basic_info.lease_type |
text | important | — |
basic_info.execution_date |
date | — | — |
basic_info.governing_state |
text | — | — |
parties
| Path | Type | Priority | Allowed values |
|---|---|---|---|
parties.landlord_name |
text | important | — |
parties.landlord_address |
text | — | — |
parties.tenant_name |
text | critical | — |
parties.tenant_address |
text | — | — |
parties.guarantor_name |
text | — | — |
parties.guarantor_address |
text | — | — |
parties.property_manager_name |
text | — | — |
parties.property_manager_contact |
text | — | — |
premises
| Path | Type | Priority | Allowed values |
|---|---|---|---|
premises.property_name |
text | — | — |
premises.property_address |
text | important | — |
premises.premises_description |
text | — | — |
premises.suite_unit |
text | — | — |
premises.floor |
text | — | — |
premises.county |
text | — | — |
premises.property_type |
text | — | — |
premises.rentable_sf |
area | critical | — |
premises.usable_sf |
area | — | — |
premises.parking_spaces |
count | — | — |
lease_term
| Path | Type | Priority | Allowed values |
|---|---|---|---|
lease_term.commencement_date |
date | critical | — |
lease_term.rent_commencement_date |
date | important | — |
lease_term.possession_date |
date | — | — |
lease_term.expiration_date |
date | critical | — |
lease_term.initial_term_months |
count | important | — |
lease_term.free_rent_months |
count | important | — |
lease_term.holdover_rate |
percent | — | — |
term_certainty
| Path | Type | Priority | Allowed values |
|---|---|---|---|
term_certainty.commencement_status |
enum | — | "" | confirmed | estimated | contingent |
term_certainty.expiration_status |
enum | — | "" | confirmed | estimated | contingent |
term_certainty.area_status |
enum | — | "" | confirmed | estimated | contingent |
term_certainty.basis |
text | — | — |
term_certainty.trigger_event |
text | — | — |
term_certainty.outside_date |
date | — | — |
term_certainty.confirming_document |
text | — | — |
base_rent
| Path | Type | Priority | Allowed values |
|---|---|---|---|
base_rent.initial_monthly_rent |
money | critical | — |
base_rent.initial_annual_rent |
money | critical | — |
base_rent.rent_per_sf |
money | important | — |
base_rent.amount_kind |
enum | — | "" | fixed | token | rent_free | referenced | variable | unknown |
base_rent.amount_text |
text | — | — |
base_rent.currency |
text | — | — |
base_rent.payment_frequency |
text | important | — |
base_rent.escalation_type |
text | important | — |
base_rent.annual_escalation_percent |
percent | critical | — |
base_rent.cpi_index_name |
text | — | — |
base_rent.cpi_floor_percent |
percent | — | — |
base_rent.cpi_ceiling_percent |
percent | — | — |
base_rent.percentage_rent_rate |
percent | — | — |
base_rent.breakpoint_sales_amount |
money | — | — |
base_rent.rent_review_date |
date | — | — |
base_rent.review_assumptions |
text | — | — |
base_rent.rent_schedule |
list | — | array |
operating_expenses
| Path | Type | Priority | Allowed values |
|---|---|---|---|
operating_expenses.expense_type |
text | important | — |
operating_expenses.base_year |
text | — | — |
operating_expenses.pro_rata_share |
percent | important | — |
operating_expenses.expense_stop_psf |
money | — | — |
operating_expenses.estimated_opex_psf |
money | — | — |
operating_expenses.estimated_annual_opex |
money | important | — |
operating_expenses.cam_cap_percent |
percent | important | — |
operating_expenses.cam_cap_basis |
enum | — | "" | cumulative | non_cumulative | compounding |
operating_expenses.cam_exclusions |
list | — | array |
operating_expenses.admin_fee_percent |
percent | — | — |
operating_expenses.property_tax_responsibility |
enum | important | "" | landlord | tenant | shared |
operating_expenses.insurance_responsibility |
enum | important | "" | landlord | tenant | shared |
operating_expenses.audit_right_days |
count | — | — |
security
| Path | Type | Priority | Allowed values |
|---|---|---|---|
security.security_deposit |
money | critical | — |
security.security_deposit_form |
text | — | — |
security.loc_amount |
money | important | — |
renewal_options
| Path | Type | Priority | Allowed values |
|---|---|---|---|
renewal_options.renewal_option_count |
count | important | — |
renewal_options.renewal_term_months |
count | important | — |
renewal_options.renewal_notice_days |
count | critical | — |
renewal_options.renewal_rent_basis |
text | — | — |
termination
| Path | Type | Priority | Allowed values |
|---|---|---|---|
termination.early_termination_allowed |
bool | important | — |
termination.termination_effective_date |
date | important | — |
termination.termination_notice_days |
count | critical | — |
termination.termination_fee |
money | — | — |
tenant_improvements
| Path | Type | Priority | Allowed values |
|---|---|---|---|
tenant_improvements.ti_allowance_total |
money | important | — |
tenant_improvements.ti_allowance_psf |
money | — | — |
tenant_improvements.restoration_required |
bool | — | — |
tenant_improvements.return_conditions |
text | — | — |
tenant_improvements.end_of_term_obligations |
text | — | — |
use_and_operations
| Path | Type | Priority | Allowed values |
|---|---|---|---|
use_and_operations.permitted_use |
text | — | — |
use_and_operations.exclusive_use |
text | — | — |
assignment_subletting
| Path | Type | Priority | Allowed values |
|---|---|---|---|
assignment_subletting.assignment_allowed |
text | important | — |
assignment_subletting.subletting_allowed |
text | important | — |
construction_completion
| Path | Type | Priority | Allowed values |
|---|---|---|---|
construction_completion.tenant_improvement_work |
text | — | — |
construction_completion.landlord_work |
text | — | — |
construction_completion.completion_deadline |
date | — | — |
construction_completion.permits_responsibility |
text | — | — |
construction_completion.construction_insurance_required |
bool | — | — |
utilities
| Path | Type | Priority | Allowed values |
|---|---|---|---|
utilities.tenant_responsible_for |
list | — | array |
utilities.landlord_responsible_for |
list | — | array |
utilities.utility_notes |
text | — | — |
maintenance_repairs
| Path | Type | Priority | Allowed values |
|---|---|---|---|
maintenance_repairs.landlord_responsible |
list | — | array |
maintenance_repairs.tenant_responsible |
list | — | array |
maintenance_repairs.hvac_responsibility |
enum | — | "" | landlord | tenant | shared |
maintenance_repairs.roof_structure_responsibility |
enum | — | "" | landlord | tenant | shared |
maintenance_repairs.common_area_maintenance |
text | — | — |
maintenance_matrix
| Path | Type | Priority | Allowed values |
|---|---|---|---|
maintenance_matrix.roof |
enum | important | "" | landlord | tenant | shared |
maintenance_matrix.hvac |
enum | important | "" | landlord | tenant | shared |
maintenance_matrix.parking_lot |
enum | important | "" | landlord | tenant | shared |
maintenance_matrix.foundation_structure |
enum | important | "" | landlord | tenant | shared |
maintenance_matrix.plumbing |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.electrical |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.windows_glass |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.exterior |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.interior |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.landscaping |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.pest_control |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.janitorial |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.elevator |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.fire_life_safety |
enum | — | "" | landlord | tenant | shared |
maintenance_matrix.snow_removal |
enum | — | "" | landlord | tenant | shared |
insurance_requirements
| Path | Type | Priority | Allowed values |
|---|---|---|---|
insurance_requirements.general_liability_limit |
money | — | — |
insurance_requirements.property_insurance_required |
bool | — | — |
insurance_requirements.workers_comp_required |
bool | — | — |
insurance_requirements.landlord_as_additional_insured |
bool | — | — |
insurance_requirements.insurance_notes |
text | — | — |
default_remedies
| Path | Type | Priority | Allowed values |
|---|---|---|---|
default_remedies.monetary_default_cure_days |
count | — | — |
default_remedies.non_monetary_default_cure_days |
count | — | — |
default_remedies.late_fee_percent |
percent | — | — |
default_remedies.late_fee_fixed_amount |
money | — | — |
default_remedies.interest_rate_on_late_payments |
percent | — | — |
default_remedies.landlord_remedies |
text | — | — |
default_remedies.tenant_remedies |
text | — | — |
warranties
| Path | Type | Priority | Allowed values |
|---|---|---|---|
warranties.landlord_warranties |
text | — | — |
warranties.tenant_warranties |
text | — | — |
warranties.warranty_notes |
text | — | — |
legal_provisions
| Path | Type | Priority | Allowed values |
|---|---|---|---|
legal_provisions.estoppel_required |
enum | important | "" | yes | no |
legal_provisions.estoppel_response_days |
count | — | — |
legal_provisions.snda_required |
enum | important | "" | yes | no |
legal_provisions.subordination_automatic |
enum | — | "" | yes | no |
legal_provisions.force_majeure_present |
enum | — | "" | yes | no |
legal_provisions.force_majeure_summary |
text | — | — |
legal_provisions.holdover_consent_required |
enum | — | "" | yes | no |
legal_provisions.holdover_summary |
text | — | — |
legal_provisions.guaranty_present |
enum | important | "" | yes | no |
legal_provisions.guaranty_type |
text | — | — |
legal_provisions.guaranty_capped_amount |
money | — | — |
legal_provisions.guaranty_summary |
text | — | — |
legal_provisions.attorneys_fees_prevailing_party |
enum | — | "" | yes | no |
legal_provisions.jury_trial_waiver |
enum | — | "" | yes | no |
legal_provisions.relocation_right |
enum | — | "" | yes | no |
legal_provisions.right_of_first_refusal |
enum | important | "" | yes | no |
legal_provisions.right_of_first_offer |
enum | — | "" | yes | no |
legal_provisions.purchase_option |
enum | important | "" | yes | no |
legal_provisions.purchase_option_summary |
text | — | — |
legal_provisions.co_tenancy_clause |
enum | — | "" | yes | no |
legal_provisions.casualty_restoration_days |
count | — | — |
legal_provisions.casualty_summary |
text | — | — |
legal_provisions.condemnation_summary |
text | — | — |
legal_provisions.environmental_provisions |
text | — | — |
legal_provisions.dispute_resolution |
text | — | — |
legal_provisions.notice_method |
text | — | — |
additional_provisions
| Path | Type | Priority | Allowed values |
|---|---|---|---|
additional_provisions |
list | — | array |
Every parse is checked for contradictions, gaps and document-integrity problems, and
the findings are returned on the response. Branch on code,
not on the message: the codes below are stable, the wording is not.
A useful pattern is to hold anything with an error for human review and ingest the rest, since an error means the lease as recorded contradicts itself and one of the two values is wrong.
| Code | Level | Meaning |
|---|---|---|
expiration_before_commencement |
error | Expiration is on or before commencement — A term cannot end before it begins. Check both dates against the lease. |
date_before_start |
error | Rent starts before the term does — Rent commencement is earlier than lease commencement. Usually the two were read from different clauses. |
missing_critical_field |
error | A critical value is missing — Every derived figure that depends on this value is unavailable until it is filled in. |
ocr_short_upload |
error | Fewer pages than the document says it has — The footer states a page count higher than what was uploaded. The end of a lease is where the signatures and exhibits live. |
amendment_conflict |
error | Amendments conflict — Two amendments change the same value with no way to tell which governs. A person has to decide. |
possession_after_commencement |
warning | Possession is after commencement — The tenant takes possession after the term has started, which is unusual and often a misread date. |
term_length_mismatch |
warning | Stated term does not match the dates — The stated number of months disagrees with the gap between commencement and expiration. |
rent_arithmetic_conflict |
warning | Monthly and annual rent disagree — Twelve times the monthly rent is not the annual rent. One figure was misread. |
rent_psf_conflict |
warning | Rent per square foot disagrees with the annual rent — The stated rate per square foot does not reconcile with the annual rent and the area. |
escalation_implausible |
warning | Escalation rate looks implausible — An annual increase outside roughly 0-25% is usually a percentage read as a fraction, or the wrong number entirely. |
pro_rata_implausible |
warning | Pro-rata share looks implausible — A share above 100% cannot be right. Check whether a fraction was read as a percentage. |
percent_unit_unclear |
warning | A percentage may have been read as a fraction — The value is below 1%, and the lease does not print it as a percentage anywhere, so it may be a fraction: 0.05 meaning five percent. Where the document settles it we correct it automatically; here it does not, and a half-percent fee is just as plausible as the alternative. |
area_may_be_building_area |
warning | The premises area may be the building's — The only place this figure appears in the lease is a sentence describing the building rather than the premises, and the building holds other tenants. Extraction quotes the document accurately here -- the question is whose square footage it is. Check the premises clause: where it defers the area to a schedule or exhibit, the right answer is usually that this lease does not state one. |
rent_unpriced |
warning | Rent is owed but the amount is not stated here — The lease imposes rent without giving a figure -- set by an exhibit, an index, or a market review. Nothing is missing from the extraction; every rent total for this lease is a floor rather than the whole obligation, and the schedule leaves those periods unpriced instead of projecting a number the lease never agreed to. |
term_trigger_overdue |
warning | A contingent term is past its outside date — The lease set an outside date for the event that settles this term, and it has passed while the term is still recorded as unsettled. Either the event happened and nobody recorded it, or a right to terminate has arisen. |
critical_fields_unverified |
warning | Critical values are unverified — The extraction was not confident and nobody has confirmed these yet. The review queue lists them field by field. |
insurance_gap |
warning | No liability insurance requirement found — A commercial lease almost always sets a general liability limit. Its absence is usually a missed clause, not a missing obligation. |
missing_signature |
warning | No signature block found — The document may be an unexecuted draft, or the signature pages may not have been included. |
missing_exhibit |
warning | Referenced exhibits are not in the document — The lease refers to exhibits that were not uploaded. Exhibits routinely carry the rent schedule and the site plan. |
ocr_low_text_density |
warning | Very little text per page — The scan quality may have defeated OCR, which means clauses are missing rather than absent. |
ocr_page_gap |
warning | Page numbers skip — The document's own page numbering jumps, so pages are missing from what was uploaded. |
ocr_blank_pages |
warning | Some pages produced no text — Those pages were in the file but nothing could be read off them, so any clause they carried is missing rather than absent. |
ocr_low_confidence |
warning | The scan was read with low confidence — The OCR engine reported it was guessing. Figures and dates are the first things it gets wrong. |
ocr_garbled_text |
warning | The extracted text looks garbled — Failed OCR returns plausible-looking nonsense rather than nothing, which reads as text to everything downstream. |
amendment_unattached |
warning | Amendment is not attached to a lease — Its terms are recorded but are not affecting any lease, so the portfolio shows superseded values. |
deadline_imminent |
warning | A deadline falls inside 90 days — A notice window that closes unnoticed is the most expensive thing a lease administrator can miss. |
term_provisional |
info | The term is not fixed yet — A date here is anticipated or depends on an event that has not happened, so every deadline derived from it — expiration, renewal notice, termination notice — moves when it settles. Confirm it from the commencement memorandum once one exists. |
security_undocumented |
info | No security recorded — Neither a deposit nor a letter of credit was found. Often correct, occasionally a missed clause. |
insurance_limit_low |
info | Liability limit is below the market norm — Commercial leases typically require at least $1,000,000 per occurrence. |
responsibility_unallocated |
info | Major building systems are unallocated — Nobody is recorded as responsible for these systems, which is the most expensive kind of ambiguity in a lease. |
cam_uncapped |
info | Operating expenses are uncapped — The tenant reimburses operating expenses with no cap recorded, so the exposure is open-ended. |
holdover_undefined |
info | No holdover rate recorded — Without a holdover rate there is no agreed penalty for staying past expiration. |
no_assignment_clause |
info | No assignment or subletting terms found — Whether the tenant may assign or sublet affects what the lease is worth on a sale. |
ocr_rotated_pages |
info | Pages had to be rotated — Sideways pages still read, but table and heading detection degrades on them. |
deadline_passed |
info | A recorded deadline has passed — Confirm whether the option was exercised or allowed to lapse. |
lease_expired |
info | The term has ended — This lease has expired. If the tenant is still in place, a renewal or an amendment is missing. |
Invalid request format or unsupported file type.
{ "success": false, "error": "Invalid file type..." }
Invalid or missing API key.
{ "success": false, "error": "Invalid or inactive API key." }
The account cannot be charged for this request — either it has no active
licence (no_licence) or it has reached its monthly cap
(capped). Branch on code rather than the message.
Nothing is extracted or charged, so the request is safe to retry once the
cause is resolved.
{ "success": false, "error": "...", "code": "capped", "usage": { "contracts_this_month": 40, "monthly_limit": 40 }, "cost": 20.00 }
Invalid HTTP method (use POST for abstraction).
{ "success": false, "error": "Method not allowed." }
Abstraction failed due to server error.
{ "success": false, "error": "Failed to abstract lease" }
# POST a remote file URL curl -X POST 'https://leasebossai.com/api/parse.php' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "file": "https://example.com/lease.pdf" }'
# POST with file upload curl -X POST 'https://leasebossai.com/api/parse.php' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -F 'file=@lease.pdf'
Every authenticated endpoint, including both abstraction paths, shares a limit of
120 requests per API key per minute.
Responses include X-RateLimit-Limit,
X-RateLimit-Remaining and X-RateLimit-Reset; a
429 response also includes Retry-After.
Each lease contract abstracted costs
$20, invoiced monthly
alongside your platform licence. Amendments to leases already on your account are
free, and failed abstractions are not charged.
If your account has a monthly cap set, requests past it return
402 with code: "capped" rather than being charged. Caps and
licences are managed in billing settings.