API Report Card · PM Software · Methodology v1.1
Magic Door
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
Almost anything you can do in the MagicDoor screens you can do from code. You can create and update properties, units, leases and tenants, post rent charges and payments to a lease ledger, run renewals and move-outs, and drive maintenance from request through work order to vendor bill. The weak spot is being told when something changes. There are no webhooks and no what-changed-since-yesterday filter on any list, so an integration cannot subscribe to events. There is an audit-log endpoint that on paper can be paged as a change feed with before-and-after values, which is the one thing standing between this and a failing mark here, but it is undocumented outside the specification file and the run did not exercise it. Plan on polling, and treat that audit feed as something to prototype before you depend on it.
2 · Design & Reliability
It is a clean modern REST API that behaves well when you push it too hard, returning a proper 429 that tells you exactly how long to wait. Where it will hurt you is production hardening. If a payment-posting call times out and your script retries it, you get a duplicate, which the run proved by creating the same property twice. There is no versioning, so MagicDoor can change the API underneath you with no notice and no policy saying they will not. Two people or two automations editing the same record overwrite each other with no conflict warning. There is no status page, so when something breaks you cannot tell whether it is you or them. And the published schemas disagree with themselves about whether a property id is a number or a string, which is the kind of thing that generates a client library that quietly corrupts your identifiers.
3 · Access Control
Key management itself is good. You can mint as many credentials as you want, name them, revoke them instantly yourself, and there is a real staging environment so you can build without risking live data. But the part that matters most for safe automation does not work. MagicDoor lets you create a key labelled read-only, and the API holding your portfolio does not honour that label. The run created a key restricted to reading audit records and it went on to create a property and read every tenant. You cannot safely hand a MagicDoor key to a contractor, a third-party app or an AI agent on the assumption it can only look. Treat every key you issue as a full-access admin credential.
4 · Docs & AI-Ready
This is the weakest part of MagicDoor's API, and it is a documentation problem rather than a capability problem. The API underneath is large and well built, but MagicDoor publishes nothing about it: no developer site, no reference, no examples, no changelog, and no mention of the API in any of their 79 help articles. Three-quarters of the endpoint descriptions are just the function name repeated. The one genuinely valuable asset is a complete machine-readable specification covering every endpoint, which is what a coding tool needs to generate a client, but nothing tells you it exists, it never describes what an error looks like, and its own server addresses are wrong for most of the services. Anyone building here should expect to ask MagicDoor directly for the specification files and base URLs, and to get no warning when something changes.
5 · Access & Cost
Nothing stands between you and the API. It is included on every plan including the cheapest, MagicDoor explicitly advertises no gated features, and you can create and revoke your own keys without talking to anyone. This is the best-scoring category in the report.
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
13.1 / 15Object coverage
weighted coverage = 98.7% (37.5 of 38 weight), no critical object absent. Every critical object carries full write operations; only inventory is read-only. [endpoint inventory across the 17 company-facing specifications; GET /company-app/properties verified live]
Core operational actions
weighted coverage = 100% (inventory marked N-A within this sub-map as a generated report). All three critical write workflows present. Verified live: POST /company-app/properties created id 1547630408379088896, PUT renamed it, GET confirmed both. Ledger and lease writes documentation-graded per the hard-exclusion list. [H5, H3]
Delete or lifecycle actions
weighted coverage = 100%. Verified live: DELETE /company-app/properties/{id} returned 200 and the record left the collection. Remaining lifecycle actions documentation-graded. [H10 to H14]
Change notification
There is no push mechanism. Across all 19 services only four webhook paths exist, and all are inbound endpoints where TransUnion and bank-feed providers post into MagicDoor; no subscription-management endpoint and no event catalogue exist. No operation among the 1,510 accepts an updated-since, modified-after or delta parameter; only created.start/created.end and closedAfter. The mechanism that carries this to partial rather than no is GET /company-portal/audit-entries on the audits service, whose entityType and entityId filters are declared optional and whose response returns AuditEntryAction of created, updated or deleted, per-field oldValue/newValue diffs, occurredAt, a cross-entity names map spanning tenants, owners, vendors, property managers, portfolios, properties, units and leases, and a nextCursor for continuation. That is a documented cursor-paginated change feed. It was not exercised in the live battery, its entityType values are not enumerated, and no ordering or retention guarantee is stated, so it does not reach yes. [G6, G9, specs/audits/CompanyPortal.json]
Category 2 · Design & Reliability
4.1 / 10Modern API conventions
Resource-oriented REST over HTTPS with standard verbs and JSON, described by OpenAPI 3.0.4. Verified live across GET, POST, PUT and DELETE.
Consistent typing
Live payloads are type-clean: totalRent: 1650 and currentBalance: 1650 are numbers, active: true is boolean, and 19-digit snowflake identifiers return as strings. The exact limitation is that the published schemas are not internally consistent about identifier types. 851 path parameters declare identifiers as integer against 273 as string, and 12 identifier names are declared with both types on different endpoints, including propertyId, leaseId, tenantId, unitId, ownerId, vendorId and portfolioId. Separately, 11 company-facing fields carrying format: snowflake are typed integer while 350 are typed string. A 19-digit snowflake typed as a JSON integer exceeds JavaScript's safe integer range. [specs/apiportal/CompanyApp.json, specs/auth/CompanyPortal.json]
Structured errors
Validation failures return a correct RFC 9457 application/problem+json body with per-field messages and an echoed traceId [D1]. The exact limitations: no populated stable machine-readable error code, only a generic RFC hyperlink identical on every 400; error shapes vary, and one auth-service 400 additionally returned detail, instance and an exception object leaking an internal .NET ArgumentException [D4]; a 404 and a 401 both returned completely empty bodies [D2, D3]; and none of the 1,510 operations documents any non-200 response [G1].
Duplicate prevention
Verified live: the identical property-create payload sent twice with no intervening change produced two distinct records, ids 1547630408379088896 and 1547630412229459968 [E5]. Zero header parameters are declared across all 1,510 operations, so no idempotency key header exists [G2]. The single idempotency mechanism in the surface is a body field, PayCompanyInvoiceDto.idempotencyKey on POST /company-app/invoices/{billId}/pay, which protects paying MagicDoor's own subscription invoice and not one operator-consequential write.
Graceful handling under load
Every response carries x-rate-limit-limit, x-rate-limit-remaining and an ISO x-rate-limit-reset [C2]. Verified live by exhausting the limit: request 101 in a one-minute window returned HTTP 429 with a machine-readable retry-after: 40 [D5]. Scored on observed behavior; this behavior is documented nowhere, which is penalized in Category 4.
Pagination for large collections
A consistent envelope (items, totalCount, totalPages, page, pageSize) is used by 71 collection endpoints and works live [C1, C3]. The exact limitations: 100 other collection-returning GETs deliver a bare unpaginated array instead [G8, C5]; only 2 of roughly 600 GETs accept any sort or order parameter [G7]; no stable ordering guarantee is stated anywhere; and the staging account held only 2 properties, 4 units and 3 tenants, so traversal of a genuinely large collection was never exercised.
Bulk or incremental export
Full datasets are retrievable without per-record calls via 27 report endpoints, with rent roll verified live returning every property and unit in one response [C6, G13], plus 9 /batch fetch-by-id endpoints. The exact limitation: no async export job, no CSV or file export, and no incremental sync of any kind [G6], so every refresh is a full re-pull.
Webhook security and delivery reliability
No operator-facing webhooks or events exist [G9]. Their absence is scored in C1.4 and is not double-counted here.
Concurrency and conflict control
Zero header parameters are declared, so there is no ETag or If-Match [G2]. No 409 semantics are documented; all 1,510 operations document only a 200 [G1]. No concurrency limits are published. Two version integer fields exist, on DepositSlipTransactionSnapshotDto and ManualReconciliationTransactionSnapshotDto, but both are read-only snapshot records with no If-Match or 409 path to use them with, so they are not concurrency tokens.
Versioning and backward compatibility
No path carries a /vN/ segment, every specification's info block contains only a title with no version, and no version header is documented [G4]. No backward-compatibility policy, deprecation window or notice mechanism exists.
Request traceability
Every response carries a unique x-trace-id, echoed into error bodies as traceId [C2, D1, D4]. The exact limitation: the header is declared in none of the 1,510 operations [G2] and no published support channel references it, so an operator has no documented way to have it used.
Service availability and status transparency
No public status page. status.magicdoor.com serves nothing and the 294-URL sitemap contains no status, uptime, incident-history or SLA page [I4, I1].
Category 3 · Access Control
3 / 5Read-only credentials
A read-only credential can be requested but is not enforced, so it is not read-only. CreateApiKeyDto accepts a permissions array, and a credential created with {"permissions":["properties:read"]} returned a JWT correctly carrying "permissions":"properties:read". That credential then executed POST /company-app/properties and created a real property, HTTP 200 [F5]. Confirmed with a second, differently scoped credential limited to audits:read, which also created a property and read the full tenant list [F6]. Both test properties were deleted and both credentials revoked. Evidence obtained via the Step 10 disclosure recorded in the run metadata.
Scoped credentials
Scope is declarable against a granular 144-permission catalog across 53 categories [F1], and it is enforced by the auth service, which correctly refused the audits:read credential with 403 on GET /company-portal/api-keys [F6]. But the business API at api.portal.magicdoor-test.com/company-app/*, which holds every property, unit, lease, tenant and ledger, ignored the scope entirely on two independent tests [F5, F6]. In practice every credential is all-or-nothing over the whole portfolio, for reads and writes alike. Same disclosure as C3.1.
Multiple keys
Four distinct credentials coexisted, each with its own id, name, creation and last-used timestamps [F4, F5, F6, F7].
Rotation and revocation
Fully self-serve. Verified live: POST /company-portal/api-keys minted a credential, DELETE /company-portal/api-keys/{id} revoked it, re-exchanging the revoked credential returned 401, and the listing showed a populated revoked timestamp [F7]. Rotation is create-new plus revoke-old. CreateApiKeyDto also declares an expires field, but every attempt to use it failed with HTTP 400 ("The UTC Offset for Utc DateTime instances must be 0"), so time-boxed credentials are declared but were never made to work [D4, F3].
Test and production isolation
A separate staging environment exists with its own auth and service hosts and its own credentials [B1, B2]. Verified live: the staging credential was rejected with HTTP 401 by the production host auth.magicdoor.com [A4].
Category 4 · Docs & AI-Ready
1.3 / 5Complete self-serve reference
There is no publicly accessible API reference. The sitemap lists 294 URLs including 79 help articles, and not one concerns the API, developers, webhooks or integrations [I1]. No documentation subdomain exists [I3]. The only reference material is a per-service Swagger UI on hostnames advertised nowhere, located in this run only by decoding a minified service registry out of the company portal's JavaScript bundle [B2, run metadata disclosure]. Even once found, 1,142 of the 1,510 operation descriptions (76%) are the operationId echoed back verbatim rather than prose, only 522 of 9,508 DTO properties (5.5%) carry any description, there are zero worked examples [G12], no error response is documented [G1], and the authentication note is a single line that never explains the token-exchange flow [G10].
Machine-consumable path
Complete OpenAPI 3.0.4 specifications exist for 19 services, are fetchable without authentication, and cover all 1,510 company-facing operations with typed schemas, enums and validation constraints [B3, B4, G11]. The exact limitations that require substantial manual correction: not one operation declares any error response, so a generated client models only the success path [G1]; there are no examples [G12]; identifier types conflict across endpoints (see C2.2); and the declared servers[0].url omits the path prefix for the 14 services routed under services.magicdoor-test.com/<name>, so a generated client would call the wrong URL [B4, B7]. No official SDK was found, though no SDK search was performed [I9]. The pricing page advertises "API/MCP Access", but no MCP server exists in any specification, in the service registry, or at the endpoints tested [I8].
AI-readable documentation
No llms.txt (404) or llms-full.txt [I2], no per-endpoint Markdown, no downloadable documentation corpus [I1]. The OpenAPI files are credited under C4.2 and are not counted twice.
Kept current
17 operations carry deprecated: true and one DTO field carries a migration instruction ("[DEPRECATED] Use ImageSessionId instead") [G5], which is genuine first-party evidence that the specification is maintained as the API changes. The exact limitation: there is no changelog, no release notes, no versioning notes, no dates, no deprecation policy or window, and no channel through which a change would be announced [I5], so a builder has no way to learn that the API has changed.
Category 5 · Access & Cost
15 / 15Self-serve API key
Credential creation is self-serve with no sales call, support ticket or approval step. Verified live: credentials were created and revoked over HTTP [F5, F6, F7, F8]. The api-keys endpoints sit on the CompanyPortal audience surface [F2] and api_keys:read, api_keys:write and api_keys:delete are ordinary CompanyPortal permissions [F1]. Disclosed limitation: the company-portal web UI was not accessed in this run, so the mechanism by which an operator obtains a first credential was not directly observed [F8].
Not commercially gated
API access is included on every plan. The pricing comparison table contains a row reading verbatim "API/MCP Access: Included / Included / Included", alongside "All plans include full access to the MagicDoor platform" and "No tiers, no gated features" [I6]. Pricing is $2.50 per unit per month (Advanced) and $3.50 (Professional) month to month, or $1.50 and $2.50 with a one-year contract, Enterprise custom, with a one-time onboarding fee of $500 / $500 / $1,000 and a 25-unit minimum. No tier gates the API.
What works
- Fully verified in a real sandbox: a property was created, renamed and deleted live
- Roughly 1,500 company-facing operations covering essentially the whole product
- API access included on every plan, from $1.50 per unit per month on an annual contract
- Self-serve key creation and instant self-serve revocation, both verified live
- A real staging environment, proven isolated when its key was rejected by production
- Rate limiting done properly: a real 429 carrying a machine-readable retry-after
- Complete OpenAPI 3.0.4 specifications for 19 services, fetchable without a login
- Every response carries a unique trace id, echoed back into error bodies
- Full lease lifecycle in the API: activate draft, renewals, move-outs with accept and reject
- Validation errors return a proper RFC 9457 body with per-field messages
What to watch
- A key created as read-only was not enforced: it created a property and read every tenant
- Scopes are ignored by the API holding your portfolio, so every key is effectively full admin
- No idempotency: the identical property-create payload sent twice produced two records
- No webhooks and no updated-since filter anywhere, so every integration polls
- No versioning at all, and no backward-compatibility or deprecation policy
- No concurrency control, so two writers silently overwrite each other
- No public status page: status.magicdoor.com serves nothing
- No published API documentation, and none of the 79 help articles mention it
- 76% of endpoint descriptions are the function name repeated, with zero worked examples
- The specifications' own server addresses are wrong for 14 of the 19 services
The bottom line for a property manager
MagicDoor has a genuinely capable API hiding behind almost no documentation. Nearly everything the product does is reachable from code across roughly 1,500 operations, and it is not just readable: the run created, renamed and deleted a property live, and you can post rent charges and payments to a lease ledger, run renewals and move-outs, and drive maintenance from request through work order to vendor bill. Access is the easiest of any platform in this category, included on every plan from $1.50 per unit per month on an annual contract, with self-serve keys and a real staging environment to build against. The two things you cannot rely on today are event-driven automation and safe delegation. There are no webhooks and no what-changed-since filter, so integrations must poll, and the audit feed that looks like it could fill the gap is undocumented and untested. There is no idempotency protection, so a retried payment call will duplicate. Most seriously, the run created an API key scoped to read-only and it created a property and read every tenant, so treat every key you issue as a full-access admin credential and do not hand one to a third-party app or an AI agent expecting it to be limited. MagicDoor is not evidenced as a bank and does not hold your money. It is the software and the ledger of record; your funds sit in your own trust and operating bank accounts, connected through Plaid, with card and ACH processing run by Payabli and Stripe. Its trust accounting is unusually well specified for a platform at this price, and the API exposes the matching reconciliation, journal-entry and owner-distribution workflows, though this run verified the object surface rather than the accounting behaviour itself. The 73 reflects a strong, buildable product surface held back by an operability and documentation gap rather than by missing features: enforce the key scopes that already exist, add webhooks and idempotency, publish a developer reference, and this would be among the better property management APIs available. Until then, plan on asking MagicDoor directly for the specification files and base URLs, budget for polling, and keep your keys tightly held.
Check it yourself.
Both files behind this page, in full.
Magic Door’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 Magic Door 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.