API Report Card · Listings, Applications & Tenant Screening · Methodology v1.1
RentEngine
Where the points came from.
Five categories, each worth a fixed share of the 100 points. A category earns the fraction of its checks it passes, times its maximum.
Functional Coverage
Design & Reliability
Access Control
Docs & AI-Ready
Access & Cost
Letter grades are absolute, never curved.
The same numeric bands apply to every platform. Nothing here is scored relative to the rest of the board.
What this means for you.
One paragraph per category, in plain language.
1 · Functional Coverage
You can see everything and change almost nothing that matters most in a leasing tool. Reading is excellent: applications, screening status, the whole funnel, and rich webhooks that tell you the moment an application is approved or a lease is signed. But you cannot submit an application, record a screening decision, approve or reject an applicant, or move a prospect through a lease stage from your own code. RentEngine says this is deliberate and compliance-driven for screening, which is a fair reason, but the effect on what you can build is the same: your automations can watch and report, not decide and act.
2 · Design & Reliability
The strongest part of the API and genuinely well built. Errors are machine-readable, rate limiting degrades cleanly with a Retry-After you can obey, every response is traceable to a log id you can quote to support, and the versioning promise is written down with 30 days notice before a breaking change. Three gaps will cost you engineering time: no documented ordering on paged lists, so a long sync while records change can miss or repeat rows; no bulk export, so a full extract means paging everything; and webhooks that are not cryptographically signed, so you cannot prove a payload is genuine, only that the caller knew a static secret.
3 · Access Control
The basics are covered. You can mint several keys, hand an integration a read-only one, and kill any of them yourself in seconds. Two things to plan around. A key is only ever as narrow as the user who made it, so create API keys from a purpose-built limited user rather than from your own admin login. And staging exists on paper but is not documented well enough to trust as a rehearsal space, and it is running behind production, so treat production as your only real environment and test carefully.
4 · Docs & AI-Ready
Full marks, and the reason a project here is predictable to scope. Everything a developer or an AI coding tool needs is public, current, and machine-readable: a real OpenAPI 3.1 file you can generate a client from, an llms.txt, and a live documentation server an AI agent can query directly. The changelog was updated the morning this was run. If you hand this API to a contractor or to an AI coding assistant, they will not be guessing.
5 · Access & Cost
No barrier at the door. If you are a RentEngine customer the API is part of what you already pay for, and you can issue yourself a key in under a minute without asking anyone. This is the cleanest possible result on access, and it is worth noting that this category carries the same 15-point weight as functional coverage.
Every check, and why it scored that way.
The same 27 checks are applied to every platform. What changes is which are N-A and what the core objects mean for that kind of software. Each mark below is quoted from the run's own report.
Category 1 · Functional Coverage
5.6 / 15Object coverage
weighted coverage = 53.6% (7.5 ÷ 14). Every critical object is present but each is read-only, so each scores 0.5: applications [GET /rental_application_groups], screening [RentalApplicationScreeningStatus], lease lifecycle [LeasingEvent.event_type, 45 values]; applicants 0.5, documents/e-sign 0.5, marketing/listings 1.0. No critical object is absent, and 53.6% falls in the 0.50–0.84 partial band.
Core operational actions
weighted coverage = 12.5% (2.5 ÷ 20). Two critical write workflows are entirely absent: application submission and screening decision. "Advance a lease stage" scores 0.5 on UpsertUnitRequest.status alone. Below 0.50 and critical write workflows absent — either condition alone forces no. [POST /leasing_events description: "Currently supported event types: Assign to User… Application Received"; no POST/PUT/PATCH on /rental_applications*]
Delete or lifecycle actions
weighted coverage = 50.0% (4.5 ÷ 9). Application approve/reject is a critical lifecycle action and is absent, which forces no regardless of the percentage. Present: unit status transitions [UpsertUnitRequest.status], showing cancellation [after_upsert_action.cancel_scheduled_bookings], soft-delete [UpsertFloorplanRequest.deleted, UpsertMultifamilyPropertyRequest.deleted]. Verified live: POST /showings/cancel, /showings/approve, and /showings/confirm all return 404 at 11:32 EDT on 2026-09-03, while the control GET /showings/create returns 405 (method not allowed), proving the probe distinguishes existing from absent routes.
Change notification
seven documented webhooks cover the critical and important state changes: LeasingEvents (45 event types, including "Application Received", "Application Approved", "Application Rejected", "Lease Signed", "Moved In", "Withdrawn"), RentalApplicationGroups (group.state_changed with a changes.status transition object), RentalApplications (application.state_changed), plus UnitsEvents, ProspectsEvents, LockboxEvents, MarketToolLeads. Efficient incremental polling is independently available and was verified live (updated_after honored on GET /units).
Category 2 · Design & Reliability
7.9 / 10Modern API conventions
resource-oriented JSON REST over HTTPS with a published OpenAPI 3.1.0 document [openapi: "3.1.0", 44 operations]. Live-confirmed standard status semantics (200 / 400 / 401 / 404 / 405 / 429).
Consistent typing
Exact limitation: MarketingListing types money and measurement fields as strings while the equivalent Unit fields are numbers, so the same concept carries two types across endpoints. Live-verified 2026-09-03: Unit.bedrooms = 3 (number) and Unit.bathrooms = 2 (number), while MarketingListing.beds = "2", baths = "2.5", rentAmount = "1949", depositAmount = "1949", squareFootage = "1487", applicationFee = "100" (all strings) — yet latitude and longitude on that same object are numbers, so the inconsistency is also internal to the resource. Held at partial rather than no because the affected resource is classified optional in the pre-fixed map, the typing is accurately documented in the schema, and the core Unit contract is now type-correct and matches live responses. See "Unresolved evaluator disagreements".
Structured errors
live-verified populated, stable machine codes with correct status semantics: 401 → {"error":"Unauthorized","code":"unauthorized"}; 400 → {"error":"Invalid query parameters","details":[{…"must match format \"uuid\""}],"code":"validation_error"}; 404 → {"error":"Rental application group not found","code":"not_found"}; 429 → {"error":"Too Many Requests","retryAfter":5,"code":"rate_limited"}. Documented code table at info.description § Errors. Caveat, not scored down: an unrouted path under /api/public/v1 returns the framework's HTML 404 page rather than JSON, matching the documented "unmapped statuses and non-JSON errors may omit code".
Duplicate prevention
(documentation-graded) — optional Idempotency-Key on all Bearer POST endpoints, scoped to user + method + path, with 24-hour replay of the first 2xx; same key with a different body → 422; concurrent retry in flight → 409; store unavailable → 503 rather than risk a duplicate. Declared as a header parameter on the write operations and documented at info.description § Idempotency and in llms.txt. Not observed live — verifying it requires a POST, which was not authorized.
Graceful handling under load
live-verified. A 45-request concurrent burst against GET /accounts produced 31 × 200 and 14 × 429; the 429 carried Retry-After: 5, X-RateLimit-Remaining: 0, X-RateLimit-Reset, and a structured body with retryAfter: 5. Published numeric limits: 30 req/5 s standard, 10/5 s strict, 40/24 h market tool.
Pagination for large collections
Exact limitation: no stable ordering guarantee is documented for the paginated list endpoints. limit/page_number offset pagination and an end-of-data signal are both present and were verified live (X-Has-More: true, X-Next-Page-Number: 1; pages 0 and 1 returned disjoint ids [4229, 5473] and [5474, 5475]), and the newer envelope format exposes page.has_more and page.next_page_number. Order was repeatable across two immediate identical calls, but repeatability observed is not a guarantee published, and offset paging without a documented order can skip or duplicate rows while records are being written. Only GET /rental_application_groups offers sort/direction, and only GET /calls documents an order ("newest first").
Bulk or incremental export
Exact limitation: incremental sync works on standard list endpoints but there is no dedicated bulk or export path, and updated_after reaches only three of roughly twenty list endpoints. Live-verified on GET /units: updated_after=2099-01-01 → 0 rows with X-Has-More: false; updated_after=2026-08-01 → all updated_at on or after that date; updated_after + updated_before bounding January 2026 → all rows inside the window. Also available on GET /prospects and GET /rental_application_groups. Everything else must be swept by full pagination.
Webhook security and delivery reliability
Exact limitation: there is no payload signature. The only verification is an optional, static shared secret sent as X-API-Key and configured per subscription [components.securitySchemes.ApiKeyAuth]; the strings "signature" and "HMAC" appear zero times in the specification. A consumer therefore cannot verify payload integrity, only that a caller knew a secret. Retries are documented but thin — "QStash… retry delivery with exponential backoff" with no retry count, ceiling, or dead-letter behavior. Consumer replay guidance is present ("Implement idempotency in your webhook handlers"). Two of the three required elements are materially limited.
Concurrency and conflict control
Exact limitation: no optimistic concurrency exists — no ETag, If-Match, If-None-Match, or version field anywhere in the specification, and no ETag on live responses. Concurrent upserts to the same unit are last-write-wins with no lost-update protection. Credited at partial only because conflict behavior tied to concurrency is documented and declared: 409 is declared on all 11 Bearer POST operations for a concurrent same-key retry, and concurrency limits are published as rate limits. One prong of the check is met and the other is absent. See "Unresolved evaluator disagreements".
Versioning and backward compatibility
explicit /api/public/v1 path version; compatibility.md defines what will not break on v1 (paths, method semantics, documented field names and types, auth, error shape, array-versus-envelope response type), what may be added without a new version, and that breaking changes ship under a new prefix; a breaking change to or removal of a production endpoint is announced at least 30 days in advance.
Request traceability
live-verified. X-Request-Id returned on every response including errors; a client-supplied apigrader-cleanroom-20260903-abc123 was echoed exactly, and an over-length value was correctly ignored and replaced with the server's own id. Documented as "the id in RentEngine logs" and quotable to support, with a support address (eng@rentengine.io).
Service availability and status transparency
https://status.rentengine.io returns HTTP 200 and publishes six components (Application Availability, APIs, Databases, CDN, Scheduling Queues, Email Service), 90-day uptime figures, a notice history, and email / Slack / RSS / webhook subscription.
Category 3 · Access Control
4 / 5Read-only credentials
(documentation-graded) — the developer portal offers a Read-only checkbox at key creation; such keys carry a read_only JWT claim, may call GET and HEAD, and return 403 with code: "read_only_token" on POST / PUT / PATCH / DELETE [info.description § Token Permissions; CHANGELOG.md 1.4.1, 2026-09-03]. Not observed live — the supplied credential is a full-access key and creating a second key is an operator action. Limitation disclosed in the vendor's own text: "Direct Supabase REST is not gated", so the read-only claim constrains the public API surface but not that separate path.
Scoped credentials
Exact limitation: scoping is role-level only, with no per-resource restriction. A token inherits the creating user's account permissions, and the only additional axis is the binary read-only flag; there is no way to limit a key to one account, one property, or one endpoint. Account isolation is enforced by membership ("The token may only query accounts its user belongs to; requesting any other account yields 403"), which limits blast radius but is a property of the user, not a scope you choose per key.
Multiple keys
the portal presents an API Keys section listing tokens in a table, and the documentation directs operators to "Use separate tokens for different integrations or environments" [info.description § Token Security Best Practices, § Invalidating Tokens].
Rotation and revocation
self-serve revocation from the portal ("Click the 'Revoke Token' icon that looks like a trash can"); rotation is create-new-then-revoke-old, entirely self-serve. Revocation is irreversible by design.
Test and production isolation
Exact limitation: a staging environment is declared (servers[1] = https://staging-app.rentengine.io/api/public/v1, "Staging environment") and the host is live, but credential isolation is nowhere documented — no first-party material explains how to obtain a staging account or token, or whether production tokens are rejected there. Live probing also showed staging is not at parity: GET /accounts on staging returned an HTML 404 (that endpoint shipped 2026-09-02 per the changelog) while GET /showings/create returned 405, so staging serves only part of the current surface. This matches the "separate environments exist but credential isolation is unclear" definition exactly.
Category 4 · Docs & AI-Ready
5 / 5Complete self-serve reference
public, no login required. Authentication is documented end to end (obtaining, using, securing, permissions, revoking); all 44 operations carry parameter definitions and descriptions; request bodies carry worked examples on 11 of 12 operations; response samples render from schema-level examples across the reference (102 code-sample and 51 response render nodes; ProspectCallRow 15/15, NoteRow 12/12, ReportingUnitRow 20/27 properties carry example values). Cross-cutting behavior — pagination in both response formats, rate limits, errors, idempotency, tracing, compatibility, webhooks, status — is documented in prose with tables and payload samples. Building against it required no reverse-engineering during this run.
Reliable machine-consumable integration path
a complete, maintained OpenAPI 3.1.0 document, downloadable as both JSON and YAML, covering all 44 operations, 7 webhooks, and 110 schemas, suitable for code and client generation. Noted, not additionally credited: a first-party documentation MCP server also exists, and there are no official SDKs. Minor defect: the document's global security is [{ApiKeyAuth: []}] (the webhook key) rather than BearerAuth; harmless in practice because all 44 operations override it with BearerAuth, but a naive generator reading only the global default would emit the wrong auth.
AI-readable documentation
https://app.rentengine.io/llms.txt (HTTP 200, text/plain) comprehensively covers auth, pagination, incremental sync, errors with the full code list, idempotency, tracing, and compatibility, and points to the machine-readable spec. Endpoint-level coverage is served by the first-party documentation MCP server at https://docs.rentengine.io/mcp, which exposes listApis, getEndpoints, getEndpointInfo, getSecuritySchemes, getFullApiDescription, and full-text search; it responded live and reports serverInfo.version 2026-09-03. Between them the API is comprehensively represented for AI retrieval. Noted: llms.txt alone would be partial, since it does not enumerate endpoints; the MCP server is what makes this a yes.
Kept current
CHANGELOG.md runs 1.1.1 → 1.4.1 dated 2026-09-03, with dated entries for every change in the preceding week and precise descriptions of behavior; the served spec reports info.version 1.4.1, matching; the documentation MCP server reports a same-day version; and compatibility.md supplies deprecation and breaking-change guidance. Currency is graded here; the versioning contract itself is graded in C2.10 and is not double-counted.
Category 5 · Access & Cost
15 / 15Self-serve API key
documented self-serve creation with no sales call, ticket, or approval step: log in to the developer portal, click "Create New API Key", name it, optionally tick Read-only, click Create, copy the token [info.description § Obtaining API Tokens]. Corroborated operationally: the operator holds a self-issued token that authenticated successfully during this run.
Not commercially gated
"Open API" is listed as an included feature of the single RentEngine platform offering on the pricing page, with no tier structure and no premium or add-on gate on API access. The reviewed materials describe one platform plan plus a one-time onboarding fee, not a tiered ladder with the API at the top.
What works
- A perfect documentation score: public OpenAPI 3.1, an llms.txt, and a first-party docs server an AI agent can query
- Changelog updated the morning of the run, with the served spec version matching
- A written promise of 30 days notice before any breaking change
- Read-only keys, multiple named keys, and self-serve revoke
- Machine-readable error codes, verified live on four separate error classes
- Rate limiting that degrades cleanly: a real Retry-After plus remaining and reset headers
- API access included in the standard plan, with a self-serve key in under a minute
What to watch
- Applications and screening are read-only: no submit, no approve, no reject
- Lease stage advance is unit status only; the events endpoint accepts 2 of 45 event types
- No DELETE verb exists anywhere in the API
- Webhooks are unsigned; verification is an optional static shared secret
- No bulk export, and the updated-since filter reaches only three of roughly twenty list endpoints
- No documented ordering on paged lists, so a long sync can skip or repeat rows
- No concurrency control: two writers to the same unit are last-write-wins
- Keys inherit the creating user's permissions, with no per-resource scoping
- One endpoint bills you: the market comps call is metered at $0.50 per successful request
The bottom line for a property manager
Today you can build reliable read-and-report automation on RentEngine and very little else. Pull your units, prospects, showings, applications and screening outcomes, receive webhooks the moment an application is approved or a lease is signed, and push units, prospects, showings, lockbox codes and notes back in. What you cannot do from your own code is the part that decides anything: submit an application, obtain or record a screening decision, or approve, reject or advance an applicant. RentEngine says the screening path is deliberately closed for compliance, which is a legitimate reason, but the practical result is that your automations can watch and report while a human still clicks the buttons that matter. The API's biggest strength is craftsmanship everywhere except coverage: genuinely excellent documentation, a current OpenAPI spec, machine-readable errors, honest rate limiting, request ids you can quote to support, a written 30-day breaking-change promise, and no cost or sales barrier to getting a key. Its biggest limitation is that it is observational at its core, compounded by unsigned webhooks and no bulk export.
Check it yourself.
Both files behind this page, in full.
RentEngine’s full report
The complete markdown report this page is built from, including the evidence packet, the run metadata and every check in full.
Download the RentEngine reportThe grading file
The exact rubric behind every score on this page. Same file, every platform. Run it yourself and compare.
Download the methodologyFound a factual error in your grade?
Tell us and we will fix it. Every mark on this page traces to a specific piece of first-party evidence or a live API call, and the full report is published so you can see exactly what was checked and what it was checked against.
Confirmed factual errors are corrected immediately.
Everything else waits. We do not rescore piecemeal on request, because a board where some vendors have been re-run and others have not is not a fair comparison. Shipped improvements, changed documentation and disagreements about judgement all go into the next full rerun.
Contact us with a factual errorMethodology inspired by SaaStr’s AI Agent API Report Card. Sponsored by Column.