API Report Card · Maintenance · Methodology v1.1
Property Meld
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 about your maintenance operation, and you can create work orders, complete them, and manage units, properties, residents, owners, vendors and tags. Creating, updating and deactivating a property and a unit worked exactly as documented under live test. What you cannot do is cancel a work order, and assigning a vendor or technician is possible only through a field that is undocumented and untyped. Scheduling, estimate approval and invoice approval all belong to the vendor's side of this API. There are no webhooks, so automations must poll.
2 · Design & Reliability
A clean, predictable REST design with a real status page, but your code has to defend itself. Field types do not always match the published schema, error bodies come in three shapes with no machine-readable code, posting a duplicate tag name crashes with a 500 rather than a 400, page size is silently capped at 500, and there is no way to detect a concurrent edit. Idempotency keys do work, but only with the header spelling used in the recipe, not the one in the guide.
3 · Access Control
You can make separate keys for separate tools and revoke any of them yourself, both self-serve. But every key carries full read and write power over the whole account. You cannot hand an AI agent a read-only or limited key, and there is no sandbox, which is why this run had to work on labelled fixtures inside the live account.
4 · Docs & AI-Ready
A coding assistant can load this API well: a public OpenAPI file, an llms.txt index, and a Markdown version of every documentation page. What is missing is human explanation. 93 of the 94 operations carry no worked example, most have no description at all, one guide documents an idempotency header that does not work, and the changelog has two entries in five years.
5 · Access & Cost
A split decision. If you are on the Ops plan you can create a key in seconds without talking to anyone. Property Meld's pricing page lists API access under Miscellaneous as Ops only, and prices Ops at $2.00 per unit per month against Core at $1.60. What that difference costs a Core customer in practice was not established by the run.
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 = 79 % (16.5/21; no critical object absent). Melds 3×1.0 [OpenAPI /api/v2/meld/ GET/POST, /api/v2/meld/{id}/ GET/PUT/PATCH; Permissions guide "Melds — read, write"]; status transitions 3×0.5 [/meld/{id}/complete/ PATCH; WriteMeld.status and PatchedWriteMeld.status are readOnly; no cancel operation among the 60 paths; /meld/canceled/ is a vendor read list and returned 400 "…or have access to this url" live]; assignment 3×0.5 [WriteMeld.maintenance {"type":"array","items":{},"writeOnly":true} with no description; in_house_servicer_ids, assigned_technicians, vendor_assignment_requests all readOnly]; vendors 2×1.0 [/vendor/{id}/ PUT/PATCH/DELETE, /vendor_invite/ POST]; scheduling 2×0.5 [Permissions guide: PM "Meld actions — write (complete, invoice, media, upload URL)"; Vendor "…schedule/reschedule/cancel"]; residents 2×1.0 [/resident/ GET/POST and {id} GET/PUT/PATCH/DELETE]; units/properties 2×1.0 [observed live: POST /property/ 201 id 1761925, POST /unit/ 201 id 1978373, PATCH 200 on both, DELETE 204 on both]; estimates 1×0.5 [Permissions: PM "Invoices, expenditures, estimates — read"]; invoices 1×1.0 [/meld/{id}/invoice/ POST/PATCH; PM "Meld actions — write (… invoice …)"]; owner approval 1×1.0 [WriteMeld.owner_approval_status writable; /owner/ CRUD]; tags 1×1.0 [observed live: POST 201, PATCH/PUT 200, DELETE 204].
Core operational actions
(controlled live for property, unit, tag; documentation for meld items) — weighted coverage = 79 % (16.5/21; no critical write workflow absent). Create meld 3×1.0 [POST /meld/, WriteMeld]; assign 3×0.5 [write-only untyped maintenance array, above]; complete 3×1.0 [PATCH /meld/{id}/complete/, PatchedMeldComplete{is_complete, completion_notes, …}]; vendors 2×1.0; scheduling 2×0.0 [PM level cannot write schedules, Permissions guide]; residents 2×1.0; units/properties 2×1.0 [live: create 201, PATCH maintenance_notes 200 and persisted on GET]; estimates 1×0.0 [PM read]; invoices 1×1.0; owner approval 1×1.0; tags 1×1.0 [live: create 201, PATCH and PUT rename 200 and persisted].
Delete or lifecycle actions
(controlled live for deactivations; documentation for meld items) — weighted coverage = 55 % (10.5/19), but a critical lifecycle action (cancel a work order) is absent. Complete 3×1.0 [/complete/]; cancel 3×0.0 [no endpoint; status read-only in WriteMeld/PatchedWriteMeld/PatchedMeldComplete; Status5c6Enum lists MANAGER_CANCELED but no operation sets it]; reassign 3×0.5 [maintenance write-only field]; appointment schedule/cancel/reschedule 2×0.0 [vendor-level only, Permissions guide]; vendor deactivate 2×1.0 [DELETE /vendor/{id}/]; resident/unit/property/owner deactivate 2×1.0 [live: DELETE /unit/1978373/ 204 → GET 404; DELETE /property/1761925/ 204 → GET 404]; estimate accept/reject 1×0.0 [Vendor: "accept/reject — write"; PM: read]; invoice approve/decline 1×0.0 [PM: read]; owner-approval status change 1×1.0; tag delete 1×1.0 [live: DELETE 204 → GET 404, list back to baseline].
Change notification
no webhooks or events exist [OpenAPI: 0 occurrences of "webhook"; llms.txt index has none; help-center search "webhook" = 0 results; verification search none]. Efficient incremental polling exists and was verified live: GET /meld/?updated__gte=2026-08-25T00:00:00Z → 516 records, 0 violations, plus status, completed__gte, marked_complete__gte, scheduled__gte, vendor_scheduled__gte filters [OpenAPI meld_list parameters]; updated__gte on /unit/, /property/; last_updated_gte on /vendor/, /resident/, /invoice/, /estimates/ [live step 3]. Not available on work logs, expenditures, projects, owners, tags, files.
Category 2 · Design & Reliability
5 / 10Modern API conventions
resource-oriented REST over HTTPS with GET/POST/PUT/PATCH/DELETE, JSON bodies, path version /api/v2/, action sub-resources (/complete/, /accept/) [OpenAPI paths; live 200/201/204 semantics on reads and writes].
Consistent typing
types vary between the published schema and live responses on core fields, and between schemas for the same field. Live meld detail: assigned_technicians returned an array, schema says string; merged_meld returned an object, schema says string [MeldSerializerDetail; live GET /meld/13755005/]. Estimates: total declared string but returned as a JSON number, while total_w_markup is declared number and pm_fee is a decimal string in the same record [EstimateSerializerList; live GET /estimates/?limit=1]. maintenance_limit is string in ReadProperty but number/double in WriteProperty [OpenAPI components]. Six Project fields (created, updated, coordinators, unit, prop, melds) and Vendor.allow_assignments are returned live but absent from the schema. Several non-nullable declared fields return null (integration_partner, integration_partner_id, Owner.user, MeldInvoice.payment). Query params use true/false strings on some filters but integer on others (exp, has_estimates, recurring) [OpenAPI meld_list parameters].
Structured errors
correct HTTP statuses (401, 404, 405, 400) and JSON bodies with a usable message, but no machine-readable error code and three different shapes: {"detail": "Not found."}, {"error": "X-Multitenant-Id is missing"}, {"status": ["Select a valid choice…"]} [live step 4]. Invalid limit, offset and unknown parameters are silently ignored with 200. Posting a tag whose name already exists returns an unhandled 500 {"status_code":500,"detail":"An internal server error occurred."} instead of a 400/409 [controlled live T1b]. The OpenAPI documents only 200/201/204 responses (no 4xx schemas).
Duplicate prevention
(controlled live) — the mechanism exists and works: a repeated POST /tag/ and a repeated POST /property/ with the same X-Idempotency-Key returned the stored 201 with the same id and no duplicate [controlled live T3, P1; recipe "How to use idempotency key"]. Limitation: the canonical Idempotent-requests guide documents the header as X-IdempotencyKey, and that spelling is not honored — the repeated POST with it hit the duplicate-name constraint and returned 500 on two separate attempts [controlled live T2, T1b]. A developer following the guide gets no protection; the header is also absent from the OpenAPI parameters. State-transition PATCH actions (/complete/, /accept/) cannot create duplicates.
Graceful handling under load
limits documented (50 read req/s, 30 write req/s) and "you may receive a 429 Too Many Requests… we recommend implementing exponential backoff or retry logic", but no Retry-After header and no numeric backoff guidance [Rate Limiting/Throttling guide]. Live: no rate-limit headers on any response; 272 req/s on /ping/ and 31 req/s on /meld/ produced no 429 [live step 5].
Pagination for large collections
limit/offset with count, next and previous URLs on every list endpoint [OpenAPI Paginated*List schemas; recipe "How to paginate results"; live step 2], ordering/order_by parameters. Limitations: undocumented hard cap of 500 rows per page (limit=1000 silently returns 500) and no documented default or stable ordering guarantee (ordering=bogusfield silently ignored) [live page-size and ordering probes; limit description "Number of results to return per page." only].
Bulk or incremental export
no bulk or async export path; incremental sync is possible on the main list endpoints via updated__gte (melds, units, properties) and last_updated_gte (vendors, residents, invoices, estimates) plus pagination [OpenAPI parameters; live step 3], but not on work logs, expenditures, projects, owners, tags, files or management agents [OpenAPI: those list operations expose only limit, offset, ordering].
Webhook security and delivery reliability
no webhooks or events (already penalized in C1.4).
Concurrency and conflict control
no ETag, If-Match, version field or 409 semantics documented or observed [OpenAPI: 0 occurrences of "ETag"/"If-Match"/"409"; no ETag header on any live response, including write responses; docs guides silent]. Observed but not scored here: a sub-second read-after-write lag (a GET immediately after PATCH showed the old name; a GET immediately after DELETE returned 200; both were correct seconds later) [controlled live T4, T5, T1b].
Versioning and backward compatibility
explicit path versioning (/api/v2/, prior /api/v0.0.1/) and a dated deprecation notice for v1 ("May 31, 2026: Version 1 entered its deprecation period. December 31, 2026: Support for Version 1 ends") [docs home; v1.0 llms.txt], but no published policy defining breaking vs non-breaking changes or a standing deprecation window [docs guides; verification search].
Request traceability
every response carries a unique Cloudflare CF-RAY identifier (e.g. a34816bd6adf7619-ORD) but no vendor request-id header, and the identifier is not documented or referenced for support anywhere in the docs [live step 5; docs grep for "request id/correlation": none].
Service availability and status transparency
public Atlassian Statuspage with 11 components, per-component uptime percentages (99.98 %, 100.0 %), an incident history page with 25 entries (latest 2026-09-01) and Atom/RSS feeds [status.propertymeld.com, /history, /history.atom]. Limitation noted: no API-specific component.
Category 3 · Access Control
2.5 / 5Read-only credentials
every token is issued with scope: "read write" [live token response]; the API-key screen has no scope, permission or read-only control (columns Name, Date Created, Client ID, Actions) [Nexus API Keys page, observed 2026-09-01]; access levels are assigned per company by Property Meld, not per key ("To find out which access level your company has, contact support@propertymeld.com") [Permissions guide].
Scoped credentials
a credential cannot be restricted to resources, actions or a role by the operator; the only differentiation is the company-wide access level (Property Manager / Vendor / Inspection Partner) set by the vendor [Permissions guide; API-key screen shows no per-key options].
Multiple keys
five distinct client-credential pairs coexist on the operator's account, each with its own Client ID and creation date (3/10/2026 … 9/1/2026) [Nexus API Keys page].
Rotation and revocation
self-serve: Create API Key button plus a Revoke action on every key row [Nexus API Keys page]; access tokens expire after 36,000 s [live token response].
Test and production isolation
no sandbox or test environment exists [OpenAPI servers: only "Property Meld Production Application"; docs, help-center search and verification search: none].
Category 4 · Docs & AI-Ready
3.8 / 5Complete self-serve reference
public developer hub with authentication guide (curl walk-through), all 94 operations in the reference, an OpenAPI schema, and nine recipes with worked curl examples (first request, paginate, filter, idempotency, unit CRUD, vendor invites, media upload, custom report) [docs.propertymeld.com guides, reference, recipes]. Limitations: reference pages are auto-generated schema dumps — 93 of 94 operations have no worked request/response example and most have no description [OpenAPI: 1 operation with an inline example; /complete/, /accept/, /schedule/, PUT/PATCH /meld/{id}/ have empty descriptions]; the assignment field maintenance is undescribed and untyped; no 4xx responses are documented; the filter recipe's "Response Example" is a placeholder {"success":true}; the idempotency guide names a header that does not work [controlled live].
Reliable machine-consumable integration path
a complete, server-generated OpenAPI 3.0.3 specification is public in JSON and YAML (60 paths, 94 operations, 140 schemas, security schemes) and suitable for code or tool generation [api.propertymeld.com/api/v2/schema/; "OpenAPI Schema" guide]; the unit and property create payloads generated from it were accepted live. No official SDK and no MCP server exist [GitHub org Property-Meld: buildpacks and forks only; docs grep "SDK/MCP": none]. Schema defects noted in C2.2 require some manual correction but do not remove the path.
AI-readable documentation
llms.txt indexes every guide, reference page, recipe and changelog entry with descriptions; every page has a .md version ("Append .md to any documentation page URL"); reference .md pages embed the endpoint's OpenAPI definition [docs.propertymeld.com/llms.txt; docs home banner "For AI agents…"]. No llms-full.txt (404).
Kept current
the OpenAPI schema is generated live from the server, guide pages carry updatedAt stamps (Permissions 2026-08-20, first-request 2026-04-13, reference pages 2026-08-04), and the v1 deprecation is dated [docs]. But the changelog has only two entries in five years (2021-06-01 and 2024-04-26) and does not record the v2 endpoints, the deprecated /media/ endpoint or the 2026 v1 deprecation [docs.propertymeld.com/changelog]; help-center release notes cover the product UI, not the API.
Category 5 · Access & Cost
7.5 / 15Self-serve API key
an entitled account creates credentials itself with the Create API Key button on the Nexus API Keys screen; five keys were created this way between 3/10/2026 and 9/1/2026 [Nexus API Keys page, observed 2026-09-01]. Noted: the docs home also says "If you need Version 2 API credentials, please contact Property Meld Support", which applies to obtaining entitlement, scored under C5.3.
Not commercially gated
"API access for customer-built agent interactions" is listed under Miscellaneous as "Ops only"; Ops is the top tier at $2.00/unit/month versus Core at $1.60/unit/month [propertymeld.com/pricing feature comparison table].
What works
- Verified with real live writes on labelled fixtures, cleaned up afterwards
- Public OpenAPI 3.0.3 schema plus an llms.txt index built for AI tools
- Working idempotency keys, proven live on repeated creates
- Multiple self-serve keys, each revocable on its own
- Public status page with per-component uptime and incident history
What to watch
- No way to cancel a work order through the API
- Vendor assignment works only through an undocumented, untyped field
- No webhooks at all, so everything has to poll
- Every key has full read and write over the account, and there is no sandbox
- The idempotency guide names a header the API does not honour
The bottom line for a property manager
Property Meld is a maintenance-only tool and its API reflects that. You can build reporting, reminders, dashboards and intake automations on top of your work orders, units, residents and vendors today, you can create work orders and mark them complete, and live testing confirmed that creating, updating and deactivating properties, units and tags works cleanly. You cannot cancel a work order, you cannot reliably assign a vendor because the only field for it is undocumented, and scheduling, estimate and invoice approvals belong to the vendor's side of the API. The strengths are a public OpenAPI file, an llms.txt index AI tools can read, working idempotency keys, and self-serve keys you can revoke. The limitations are missing webhooks, full-access-only keys with no sandbox, loose typing, a guide documenting the wrong idempotency header, and an API sold only with the top plan. It holds no funds, so you still need your PMS for ledgers, owner statements and payments.
Check it yourself.
Both files behind this page, in full.
Property Meld’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 Property Meld 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.