Rent Roll API
内置验证的租金明细提取API
文档
API documentation
One endpoint does the work: upload a rent roll, get structured data back with a deterministic verification report. No async jobs, no polling — a single HTTP call.
Machine-readable spec: OpenAPI 3.0 (openapi.json) — import into Postman, Insomnia, or your codegen tool.
Authentication
Pass your API key in the X-Api-Key header (or as a bearer token). Get a key from the pricing page; manage it at your account.
X-Api-Key: rr_live_your_key_here
or
Authorization: Bearer rr_live_your_key_here
No key? The web app allows 3 free extractions/day per IP for evaluation.
POST/v1/extract
Extracts structured data from one document. Send multipart/form-data with a file field.
Supported inputs
- PDF — digital or scanned (OCR handled automatically), up to 25 MB
- Excel —
.xlsx,.xlsm - CSV, HTML
Query parameters
| Parameter | Values | Default | Description |
|---|---|---|---|
| format | json · csv · xlsx | json | Response format. csv/xlsx return a downloadable file. |
Example
curl -X POST "https://rentrollapi.com/v1/extract?format=json"
-H "X-Api-Key: rr_live_your_key_here"
-F "file=@rent-roll.pdf"
.NET SDK
Official client on NuGet: RentRollAPI.Client (netstandard2.0 / net8.0).
dotnet add package RentRollAPI.Client
using RentRollApi.Client;
using var client = new RentRollClient("rr_live_your_key_here"); var result = await client.ExtractAsync("rent-roll.pdf");
Console.WriteLine($"{result.Units.Count} units, confidence {result.Verification.DocumentConfidence:P0}"); foreach (var check in result.Verification.Checks) Console.WriteLine($"[{check.Result}] {check.Name}: {check.Detail}");
// Or get Excel / CSV directly: byte[] xlsx = await client.ExtractToXlsxAsync(stream, "rent-roll.pdf");
Response (JSON)
Every field carries a value, status (Extracted / Missing / Flagged), and confidence. The verification block is computed deterministically — totals are re-added and reconciled against what the document states, so you know when to trust the output.
{ "propertyName": { "value": "Maplewood Commerce Center", "status": "Extracted", "confidence": 0.9 }, "asOfDate": { "value": "2026-06-30", "status": "Extracted", "confidence": 0.9 }, "units": [ { "unitNumber": { "value": "101", "status": "Extracted", "confidence": 0.9 }, "tenantName": { "value": "Cedar Point Dental", "status": "Extracted", "confidence": 0.9 }, "squareFeet": { "value": 1850, "status": "Extracted", "confidence": 0.9 }, "monthlyRent": { "value": 4625.0, "status": "Extracted", "confidence": 0.9 }, "leaseStart": { "status": "Missing" }, "leaseEnd": { "value": "2028-03-31", "status": "Extracted", "confidence": 0.9 }, "occupancy": { "value": "Occupied", "status": "Extracted", "confidence": 0.9 } } ], "totals": { "unitCount": 8, "monthlyRent": 28155.0, "squareFeet": 13750 }, "verification": { "documentConfidence": 0.9, "flaggedFieldCount": 0, "allChecksPassed": true, "checks": [ { "name": "UnitCountReconciliation", "result": "Pass", "detail": "Extracted 8 units; document states 8." }, { "name": "TotalMonthlyRentReconciliation", "result": "Pass", "detail": "Computed 28,155.00 vs stated 28,155.00 (within tolerance)." }, { "name": "TotalSquareFeetReconciliation", "result": "Pass", "detail": "Computed 13,750.00 vs stated 13,750.00 (within tolerance)." }, { "name": "DuplicateUnits", "result": "Pass", "detail": "No duplicate unit numbers." }, { "name": "LeaseDateOrder", "result": "Pass", "detail": "All lease end dates follow start dates." }, { "name": "NonNegativeRents", "result": "Pass", "detail": "No negative rents." } ] } }
Errors
| Status | Meaning |
|---|---|
| 400 | Missing/empty file field, file over 25 MB, or unknown format |
| 401 | Invalid or revoked API key |
| 422 | Unsupported or unreadable document |
| 429 | Monthly quota exceeded and no prepaid credits remain (or demo limit reached) |
All errors return {"error": "human-readable message"}.
POST/v1/extract/operating-statement
Extract a T12 / operating statement (trailing-twelve-month income & expense report) into structured line items. Same inputs, auth, metering, and format options as /v1/extract — one extraction counts as one document against your quota.
Example
curl -X POST "https://rentrollapi.com/v1/extract/operating-statement"
-H "X-Api-Key: rr_live_your_key_here"
-F "file=@t12.pdf"
{ "propertyName": { "value": "Maplewood Apartments", "status": "extracted", "confidence": 0.95 }, "basis": { "value": "Accrual", "status": "extracted", "confidence": 0.9 }, "months": ["2025-08", "2025-09", "...", "2026-07"], "lineItems": [ { "label": { "value": "Gross Potential Rent", "status": "extracted", "confidence": 0.95 }, "kind": "Income", "category": "GrossPotentialRent", "monthlyValues": [ { "value": 52000, "status": "extracted", "confidence": 0.9 }, "..." ], "total": { "value": 631200, "status": "extracted", "confidence": 0.95 } } ], "verification": { "documentConfidence": 0.9, "allChecksPassed": true, "checks": [ { "name": "RowTotalReconciliation", "result": "pass", "detail": "All 15 row totals reconcile with their monthly values." }, { "name": "NoiReconciliation", "result": "pass", "detail": "EGI − OpEx matches stated NOI (within tolerance)." } ] } }
Deterministic checks: row totals vs monthly values, EGI = income sum, Total OpEx = expense sum, NOI = EGI − OpEx, non-negative expenses, and consecutive-month continuity. Line-item kind is Income, Expense, Subtotal, or Other; category normalizes labels into ~23 standard buckets (RealEstateTaxes, Insurance, Utilities, RepairsMaintenance, Payroll, ManagementFee, ...). Contra-revenue rows like vacancy and concessions are Income-kind with negative values.
MCP server (AI assistants)
RentRollAPI is also a Model Context Protocol server. Point any MCP-capable client (Claude, ChatGPT, Copilot, Cursor...) at the streamable-HTTP endpoint and it gains extract_rent_roll and extract_operating_statement tools:
{ "mcpServers": { "rentrollapi": { "type": "http", "url": "https://rentrollapi.com/mcp", "headers": { "X-Api-Key": "rr_live_your_key_here" } } } }
Omit the header to use the free 3-docs/day demo allowance. Metering is identical to the REST API.
Account endpoints
All authenticated with the same X-Api-Key header.
| Endpoint | Description |
|---|---|
| GET/api/account | Plan, monthly usage, remaining quota, prepaid credits |
| POST/api/account/rotate | Issues a new key, immediately revokes the current one (credits carry over) |
| POST/api/portal | Returns a Stripe Customer Portal URL — upgrade, downgrade, cancel, invoices |
| POST/api/credits/checkout | Returns a Stripe Checkout URL for a 25-credit top-up applied to this key |
Quotas & billing
- Subscriptions (Starter 50/mo, Pro 300/mo): quota resets on the 1st (UTC). Overage draws from prepaid credits when you have them.
- Pay-as-you-go: each extraction consumes one prepaid credit.
- Credits never expire and survive key rotation and subscription cancellation.
Data handling
Documents are processed in memory and never stored after your extraction completes. See the privacy policy.