API Report Card · PM Software · Methodology v1.1
AppFolio
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 read everything and be notified about nearly everything, and you can automate maintenance, billing, and application decisions. But the leasing money cycle stays in the AppFolio interface. There is no lease creation, no move-out, no payment posting, no voiding or reversing a ledger transaction, and no reconciliation through the API. Leases can only be updated on three fields.
2 · Design & Reliability
The strongest part of the card, and a well engineered API by any measure. Typed schemas, real idempotency keys with replay headers, exact rate-limit semantics, cryptographically signed webhooks across 20 topics, documented conflict behaviour, and a public status page. The gaps are minor: error codes mirror the HTTP status rather than naming the cause, there is no ordering guarantee on lists, the request id is undocumented, and there is no webhook retry contract.
3 · Access Control
One all-or-nothing production key per database. You can rotate it yourself, but you cannot mint a read-only key for a reporting tool, a scoped key for an AI agent, or a second key you can revoke independently. Which endpoints and even which fields your key can see is negotiated with AppFolio rather than set by you. And there is no sandbox, so you test against production with that one key.
4 · Docs & AI-Ready
A human developer with your login gets excellent documentation: 162 operations, typed schemas, worked examples, and a monthly changelog. Your AI tools get almost nothing. There is no OpenAPI spec published anywhere, no SDK, no MCP server, and the reference is a JavaScript-rendered page that returns an empty shell to anything without a browser. It is also login-gated, so it is not public.
5 · Access & Cost
The API is a premium plan feature. There is no API at all on Core, read-only on Plus, and read-write only on the top Max plan. Even once you are entitled, generating the credential is self-serve but usable access is not: endpoint and field permissions are agreed with AppFolio case by case, and webhooks and batching need a representative.
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
(reconciled; run 1 scored yes) — weighted coverage ≈ 84–87% depending on two contestable half-points, straddling the 85% yes-line; no critical object absent. All 7 critical objects live-read (200s), but leases score 0.5 as an object (3-field PATCH, no create — both independent graders held this and it is the better reading of "operations its role requires"); payments 0.5 (read-only via payables/reports); reconciliation 0–0.5 (no reconciliation resource; trust/deposit reports arguably count read-only); communications 0.0; custom fields 0.5. Resolved to partial: two of three graders, and the mark should not hinge on a contestable half-point. [1, 12, 14]
Core operational actions
(documentation-graded) — weighted 14/19 = 73.7%. Read core records 1.0 (live); post ledger charges & payments 0.5 (POST /charges + /journal_entries documented; tenant payments/receipts cannot be posted); create/update leases 0.5 (PATCH /leases/{id} — EndOn, IsMtm, RenewedOn — but no lease create); owners 1.0, bills 1.0 (incl. bulk/async), applicants 1.0, work orders 1.0 (POST + PATCH incl. WorkOrderStatus per 8/28/2026 changelog); payments 0.0. [1, 2]
Delete or lifecycle actions
(documentation-graded) — weighted 4/10 = 40%, and move-out (critical) is absent from the API (no MoveOut on tenant PATCH; no occupancy end operation). Present: work-order status transitions 1.0, application decisioning 1.0 (approved/denied/canceled/in_review/…); absent: void/reverse of ledger transactions, archive. DELETEs exist only for inspections, inventories, photos, WO attachments. [1]
Change notification
(reconciled; run 1 scored yes) — 20 signed webhook topics with create/update/destroy events; the mark turns on the denominator: over objects present, push coverage is 89.7% (only bank accounts lack a topic) → yes; over the full predetermined critical+important set (counting absent payments/reconciliation as undetectable) it is 78.8% → partial. Two of three graders used the full-set denominator; published mark is partial with the definitional disagreement disclosed below. Mandatory-filter incremental polling (live-verified), self-serve "Send Test Event", opt-in batching. [1, 12]
Category 2 · Design & Reliability
7.9 / 10Modern conventions
resource-oriented JSON REST, standard verbs incl. DELETE, worked samples. [1, 12]
Consistent typing
reference schemas are typed (string <uuid>, string <decimal>, boolean, enums; money documented as decimal-string by design; ISO 8601 mandated) and live reads matched them. [1, 12]
Structured errors
documented status table incl. custom codes (533 Data Unavailable, 701 Invalid Credential) and structured {code, message} bodies (live-confirmed, actionable); limitation: code mirrors the HTTP status rather than identifying the specific error cause (message parsing required), and the 404 shape differs ({status, error}). [1, 12]
Duplicate prevention
(documentation-graded; live retry in write plan) — full Idempotency-Key support on POST: SHA-256 body fingerprint, Idempotent-Replayed: true replay header, same-key/different-body → 422, in-flight → 409 + Retry-After, 24 h TTL, machine-readable error codes. [1 §Idempotency]
Graceful handling under load
documented 429 with Retry-After header and exact semantics (8 req/s, 256/min, 4096/hr; per-limit Retry-After values; stricter 5-per-15 s on /gl_details and /jobs); exponential backoff guidance for 503. [1 §Rate Limits, §Best Practices]
Pagination
documented page[number]/page[size] (default 1000) + next_page_path on every list endpoint, live-traversed; limitation: no stable-ordering guarantee documented and no total-count signal. [1, 12]
Bulk or incremental export
mandatory LastUpdatedAtFrom incremental pattern documented as the sync method (1970-01-01 initial import + watermarks), live-verified; plus bulk and async-bulk write endpoints and a /jobs status endpoint. [1, 12]
Webhook security and delivery reliability
(documentation-graded) — JWS PS256 detached signatures with public JWKS (documented + live key set) and duplicate-delivery guidance via event_id/batch_id; limitation: no documented retry policy (webhook logs record attempts and response codes, but no redelivery contract). [1, 9, 10]
Concurrency and conflict control
documented 409 ("conflicts with the current state of the resource — resolve and retry"), documented simultaneous-PATCH behavior (second write fails; stagger/queue guidance), documented concurrency/rate behavior. No ETag/version fields, but the check accepts documented conflict semantics + concurrency behavior. [1 §Error Codes, §Troubleshooting]
Versioning and backward compatibility
(reconciled; run 1 scored yes, both independent graders partial) — explicit path versioning (/api/v0, Reports /v2) and deprecation notices exist, but the check's yes requires a compatibility policy defining breaking vs non-breaking changes and deprecation windows — neither is documented ("removed entirely when a new API version is released", no timelines). [1 §Best Practices, 2, 14]
Request traceability
unique x-request-id on every live response and demonstrably usable with AppFolio support (2026-06 ticket); limitation: the identifier is not documented in the reference. [12, 13]
Status transparency
public status page, per-component 90-day uptime + incident history incl. "AppFolio Database APIs". [8]
Category 3 · Access Control
1.9 / 5Read-only credentials
read-only exists only as a plan tier (Plus), not as an issuable credential type; the credential UI offers no read-only option. [3, 5]
Scoped credentials
per-endpoint and per-field scoping demonstrably exists but is administered by AppFolio agreement, not operator-configurable (live 403→grant history; "fields AppFolio has not previously agreed to send… omitted"). [1, 13]
Multiple keys
one credential pair per customer database; the credential UI shows a single pair with no option to create more ("You'll need separate credentials for each customer database" — separation is per-database, not per-integration). [1, 3]
Rotation and revocation
self-serve "Regenerate Client Secret" in the Developer Space dashboard (product-interface observation; secret age displayed). [3]
Test and production isolation
(reconciled; run 1 scored no, both independent graders N-A per the check's own instruction "mark N-A when no sandbox or separate test environment exists" — none exists for operators; the partner-only sandbox is not part of the operator offering). The practical consequence — operators test against production with the sole all-powerful credential — is captured in C3.1–C3.3. [3, 6]
Category 4 · Docs & AI-Ready
1.3 / 5Complete self-serve reference
the reference is complete and example-rich (162 operations, typed schemas, worked requests/responses, guides for auth/errors/webhooks/idempotency), but it is login-gated to customers/partners, not publicly accessible. [1]
Machine-consumable path
no published OpenAPI/Swagger spec (none served to the docs SPA, none downloadable, none public), no official SDKs, no MCP server. [1, amendment log]
AI-readable documentation
no API-focused llms.txt/Markdown corpus; the reference is a client-rendered SPA that returns an empty shell to non-browser retrieval. [10, 11]
Kept current
(reconciled; run 1 scored yes, both independent graders partial — and they are right) — the changelog is rich (104 dated entries, monthly cadence through 8/28/2026, deprecation/breaking annotations), but this run demonstrated a silent breaking change: the removal of the owner_contributions/owner_distributions endpoints (live 404s) appears nowhere in it. A currency signal with a proven gap on a breaking removal is "incomplete or otherwise unreliable" → partial. [2, 12]
Category 5 · Access & Cost
7.5 / 15Self-serve API key
once entitled, credential generation and rotation are self-serve in-product (documented steps + observed UI); but usable access is not: per-endpoint/per-field entitlements require AppFolio agreement (proven by this account's /leases support-ticket history), and webhooks/batching require contacting a representative. [1, 3, 13]
Not commercially gated
(reconciled; run 1 scored no, both independent graders partial) — the check's partial bucket ("some meaningful capabilities are tier-gated") fits the evidence more precisely than its no bucket ("the API requires a premium plan"): a read-only API is available at the mid tier (Plus), while all writes require the top-tier Max plan and Core has no API. [5]
What works
- Strong Design and Reliability, 7.9 out of 10
- Real idempotency keys, with replay headers and documented error codes
- Signed webhooks across 20 topics, with a public key set
- A Reports API exposing trust account, deposit, ledger and 1099 data
- Changelog with 104 dated entries and a monthly cadence
What to watch
- No lease creation, move-out, payment posting, voids or reconciliation via API
- One all-powerful key per database, with no read-only or scoped option
- No operator sandbox, so you test against production
- No OpenAPI spec, no SDK, and docs an AI tool cannot retrieve
- Endpoint and field access is negotiated with AppFolio, not self-serve
The bottom line for a property manager
AppFolio's Database API is a well engineered read-and-notify platform with a genuinely strong operational core. Every object your business runs on is readable with typed schemas, incremental sync is the documented design, webhooks are cryptographically signed, and idempotency and rate limits are properly specified. The score is dragged down by what an operator is allowed to build. The API is locked to premium plans, endpoint and field access is negotiated with AppFolio rather than self-serve, there is one all-powerful key per database with no sandbox, AI tooling gets no spec or retrievable docs, and the leasing money cycle is absent entirely. The F reflects this rubric's heavy weighting of access, control and workflow completeness, not engineering quality. Practical read: on the Max plan this is an excellent system of record to sync from and to automate maintenance, billing and application decisions against, and the Reports API pulls trust account and 1099 data programmatically. It is not a platform you can run your whole business through, because managing trust accounts, posting payments and reconciliation stay in the interface.
Check it yourself.
Both files behind this page, in full.
AppFolio’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 AppFolio 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.