# API Report Card: Process Street Public API

## Run metadata
- Methodology version: 1.1
- Evaluating model: Claude Opus 5 (claude-opus-5)
- Date run: 2026-08-31; reconciled 2026-09-01
- **Independent runs compared: 3** (methodology step 12). All three graded the same final frozen packet `ps-2026-08-31-final`. Unreconciled run totals were 75, 72 and 70. **The published 73 is not an average** — it is the score recomputed from the reconciled check-level marks, per step 12's instruction to resolve disagreements against the final evidence rather than hide them inside an average. 21 of 26 applicable checks were unanimous; 5 were split; each split is resolved and recorded below.
- Provisional evidence-packet version or ID: `ps-2026-08-31-provisional`
- Final evidence-packet version or ID: `ps-2026-08-31-final` (frozen spec `evidence/processstreet-openapi-frozen-2026-08-31.json`, OpenAPI 3.1.0, info.version 1.1, 82 paths / 150 operations, 1,588,304 bytes)
- Evidence-discovery mode: tool-enabled discovery
- Evidence tier: **Fully verified — controlled live**
- Live-write method and safety: controlled live — operator authorization recorded in-session 2026-08-31 ("Yes — full inert plan"); all writes confined to fixtures named `APITEST-DELETE-2026-08-31` inside a purpose-created fixture folder; cleanup verified (0 APITEST records remaining across folders, pages, data sets, workflows, webhooks)
- Minimum live-test battery: **complete** (steps 1–8 all run; no step N-A)
- Live tests performed: (1) authenticate; (2) read core resources and page through `/workflows` to end of collection; (3) filtered queries `status`, `workflowId`, `name` confirmed honored; (4) six deliberate errors across four classes; (5) rate-limit and request-id headers captured; (6) create + update + delete of Page, Data Set, Data Set record, Workflow, Workflow Run, Folder; (7) identical `createWorkflowRun` sent twice with the same `referenceId`; (8) webhook registered, event fired, delivery observed in operator-controlled server log, subscription deleted
- Live tests not possible: none
- Documentation-graded checks: none in full. **Partial disclosure:** in step 8, delivery was verified from the operator's own nginx access log (`POST /ps-webhook-test` from `ProcessStreet/1.0`, 19:19:54Z), but request headers and payload could not be captured because the proxy configuration change needed to route the request to a logging listener was blocked by the operator's own sandbox policy. The C2.8 *delivery* finding is therefore live-observed; the C2.8 *signature-absence* finding is documentation-graded (0 occurrences of signature/HMAC/secret in the frozen spec; no signing mechanism described in the first-party webhooks help article).

## Final evidence packet manifest
- https://public-api.process.st/api/v1.1/docs/openapi.json (frozen locally; OpenAPI 3.1.0)
- https://public-api.process.st/api/v1.1/docs/docs.yaml (2,298,618 bytes, HTTP 200)
- https://public-api.process.st/api/v1.1/docs/index.html (Scalar-rendered reference, with `<noscript>` links to the raw spec)
- https://developer.process.st/ (302 → the reference above)
- https://www.process.st/help/docs/process-street-api/ (API guide; key creation; "Available on All plans")
- https://www.process.st/help/docs/restricted-api-keys/ (scoping; "Restricted API keys are available on Enterprise plans")
- https://www.process.st/help/docs/user-permissions/ (Admin / Builder / User / Guest role definitions)
- https://www.process.st/help/docs/webhooks/ (retry policy: "a maximum of 3 tries")
- https://www.process.st/help/docs/mcp-server/ (first-party MCP server at https://mcp.process.st/)
- https://www.process.st/llms.txt (8,995 bytes; "## API & Developer" section)
- https://www.process.st/help/llms.txt (211,972 bytes help corpus)
- https://www.process.st/help/blog/ (release notes; newest post 2026-07-15)
- https://www.process.st/help/new-api-endpoints/ (dated 2025-07-01)
- https://www.process.st/pricing/ (plan matrix and API call allowances)
- https://status.process.st/ (component status + incident history)
- https://www.process.st/industries/property-management/ (dedicated PM page)
- https://www.process.st/help/docs/property-management-pre-made-workflows/ (8 named PM templates)
- https://www.process.st/help/enterprise-reporting-api/ ("BI Integrations are available only on our Enterprise plan")
- First-party product-interface observations, RL Property Management org, 2026-08-31: Integrations page (`app.process.st/organizations/manage/integrations`); API key access page (`/users/otEeTdZnGZJEzzSmbHpD0w/manage/access`); Users & Guests (`/organizations/manage/users`); Billing (`/organizations/manage/billing`)
- Live observation logs: `evidence/live-ps/` (headers, bodies, before/after states)
- Fixed classification: `evidence/processstreet-coverage-classification-FIXED-2026-08-31.md`
- Reviewed write plan: `evidence/processstreet-write-plan-2026-08-31.md`

## Evidence-amendment log
- C1.4 / C2.8: `https://www.process.st/help/docs/webhooks/` added during controlled verification to establish the retry policy and to test for a signing mechanism, after the frozen spec was found to contain no signature evidence.
- C3.1 / C3.2: `https://www.process.st/help/docs/restricted-api-keys/` and `https://www.process.st/help/docs/user-permissions/` added, plus operator-authorized authenticated-browser observation of the Integrations, key-access, Users & Guests and Billing screens. This was done under the methodology's requirement to request login-gated documentation before finalizing a `no` or `unverified` on evidence a login gate hid. Without it, C3.1–C3.4 would have been unverified and Category 3 would have failed the 0.70 coverage gate.
- C2.10 / C4.4: `https://www.process.st/help/blog/` added to test for an API currency mechanism after the dedicated "New API Endpoints" page proved stale (2025-07-01).
- Property-management fit: `industries/property-management/` and `help/docs/property-management-pre-made-workflows/` added during the mandated industry-fit discovery pass. This changed the fit finding from `general-purpose` to `dedicated PM offering`.

## API eligibility
- Qualifying API: **yes**
- API operator: Process Street — the spec is served from the vendor's own domain and titled "Process Street Public API" [`info.title`, frozen spec; server `https://public-api.process.st/api/v1.1`]
- Access or credential issuer: Process Street, self-serve by an organization administrator ["To create an API key you must be an administrator", https://www.process.st/help/docs/process-street-api/; observed in-app: Integrations page, "New API Key" button]
- Eligibility basis: A first-party OpenAPI 3.1 specification defines 150 operations over Process Street's own objects, and a supplied key authenticated live against it — `GET /testAuth` returned `{"apiKeyLabel":"API Key #4 (RL Property Management)"}`, HTTP 200, 2026-08-31.

## Context
- Software category: **Workflow / CRM tool** (workflow, SOP and compliance-operations platform)
- What the API is for and its core objects and workflows: The API drives Process Street's process engine. Its core objects are Workflows (reusable templates), Workflow Runs (single executions of a template), the Tasks and Form Field Values inside a run, plus Data Sets, Pages, Folders and event subscriptions. The primary jobs are starting a run, reading and updating its live state, completing and assigning tasks, writing form-field data, and being notified when a run or task changes state.

## Provider and property-management fit
- What this product is: A workflow and SOP platform that turns recurring procedures into trackable checklists with forms, conditional logic, assignment and automation ["Process Street is a Compliance Operations Platform that combines document management (Docs), workflow automation (Ops), and AI-powered compliance monitoring (Cora)", https://www.process.st/llms.txt]
- Bank status, when relevant: **N-A** — not a financial product; the API exposes no accounts, balances, transactions or payment initiation
- Who provides any bank account or regulated banking service: **none** — no banking or fund-holding function is evidenced anywhere in the frozen spec or first-party materials
- What the customer actually receives: A software subscription for building and running checklist-driven processes, plus an API and MCP server over that engine. No funds, ledgers or accounts are held.
- Property-management fit: **dedicated PM offering** — the product serves a broad market but publishes a property-management industry page and PM-specific workflow templates in its own help centre [https://www.process.st/industries/property-management/; https://www.process.st/help/docs/property-management-pre-made-workflows/]
- Documented PM-specific workflows: "Tenant onboarding", "Maintenance & work orders", "Lease management & renewals", "Revenue management" [industries/property-management/]; and eight named pre-made templates — Tenant Screening, Landlord Screening, Tenant Onboarding, Landlord Onboarding, Rental Inspection, End of Tenancy Cleaning Service Guide, Tenant Move-In Process, Tenant Move-Out Process [help/docs/property-management-pre-made-workflows/]
- Trust or fiduciary workflow support, when relevant: **not documented** — the PM page's "Revenue management" refers to checklist coverage of rent collection, billing and expense tracking as *process steps*. No trust account, client-fund, security-deposit or escrow handling is evidenced, and the API exposes no ledger or money-movement objects.
- Operational role and dependencies: Process Street is the procedure layer that sits on top of a property manager's system of record; the operator still needs a PMS or accounting system (and a bank) for properties, units, leases, ledgers and funds.

## Coverage classification (fixed before inspection)
Fixed 2026-08-31 before the path list was inspected, from the methodology's default Workflow/CRM classification. Two deviations were recorded in advance: "records" was expanded into the product's distinct record types so that weighted coverage is not decided by one blended item, and "Users & groups" was added as *important* because ownership of work is inherent to a workflow tool. Full table: `evidence/processstreet-coverage-classification-FIXED-2026-08-31.md`.

| Object or workflow | Class | Weight | Present / read-only / absent |
|---|---|---|---|
| Records — Workflows (templates) | critical | 3 | Present, full CRUD + revisions, tasks, widgets, logic rules |
| Records — Workflow Runs | critical | 3 | Present, full CRUD + undelete |
| Records — Tasks inside a run | critical | 3 | Present, read + update + assignment |
| Automations / triggers | critical | 3 | Present — outgoing webhooks CRUD, incoming webhooks, scheduled workflows, logic rules |
| Custom fields — form fields and values | important | 2 | Present, read + batch update + file upload |
| Boards / pipelines — folders, status, assignment | important | 2 | Present — folders CRUD + permissions, status filters, assignees |
| Users & groups | important | 2 | **Materially read-only** — `listUsers` only; no create/update/delete, no groups endpoint |
| Records — Data Sets / records | important | 2 | Present, full CRUD + CSV import |
| Records — Pages | optional | 1 | Present, full CRUD + revisions + publish + markdown |
| Reporting / exports | optional | 1 | **Materially limited** — only `getMyWorkStats`; no reporting or export endpoints |

## Functional coverage map
- Core objects: Workflows (present), Workflow Runs (present), Tasks (present), Automations/triggers (present), Form fields and values (present), Folders/status/assignment (present), Users (read-only), Data Sets (present), Pages (present), Reporting/exports (limited)
- Primary operational workflows: start a run; update a run; complete and update tasks; write form-field values; assign and unassign users; build and publish templates; create and update data-set records; create and update pages; subscribe to events
- Principal lifecycle changes: complete task / complete run; archive or delete a run (and undelete); delete a webhook subscription; assign and unassign; publish or delete a workflow revision; delete a data-set record; delete a page

## Category 1: Functional Coverage and Usefulness: 13.1/15
- **C1.1 Object coverage: yes** — weighted coverage = **93%** (20.5 of 22 weighted points; no critical object absent). Full-CRUD critical objects [frozen spec: `/workflows`, `/workflow-runs`, `/workflow-runs/{id}/tasks/{taskId}`, `/webhooks`, `/scheduled-workflows`]. Deductions: Users scored 0.5 — only `GET /users` exists (live: returned the org user list, no write verb defined); Reporting/exports scored 0.5 — only `GET /work/stats`.
- **C1.2 Core operational actions: yes** — weighted coverage = **100%** (15 of 15). Every mutable item can be created or updated: `createWorkflowRun`, `updateWorkflowRun`, `updateTask`, `batchUpdateFormFieldValues`, `createWorkflow`, `assignWorkflowRun`, `createDataSetRecord`, `createPage`. **Observed live (controlled live):** `POST /pages` → 201; `PUT /pages/{id}` changed `description` from `BEFORE-STATE` to `AFTER-STATE-updated-by-api-test`, confirmed by fresh `GET`; `POST /data-sets` → 201; `POST /data-sets/{id}/records` → 201; `POST /workflows` → 201; `POST /workflow-runs` → 201.
- **C1.3 Delete or lifecycle actions: yes** — weighted coverage = **100%** (15 of 15). `deleteWorkflowRun` + `undeleteWorkflowRun`, run `status` transitions (Active/Completed/Archived), `deleteWebhook`, `unassignWorkflowRun`/`unassignTask`, `publishWorkflowRevision`, `deleteDataSetRecord`, `deletePage`, `completeOneOffTask`/`uncompleteOneOffTask`, `upsertApproval`. **Observed live:** `DELETE /pages/{id}` → 204 then `GET` → 404 `NotFound`; `DELETE /workflow-runs/{id}` → 200; `DELETE /workflows/{id}` → 204; `DELETE /data-sets/{id}` → 204; `DELETE /webhooks/{id}` → 200.
- **C1.4 Change notification: partial** — outgoing webhooks exist and deliver, but cover well under the yes threshold and there is **no `updated-since` filter anywhere in the API**. `POST /webhooks` accepts six triggers only: `TaskChecked`, `TaskUnchecked`, `TaskCheckedUnchecked`, `TaskReady`, `WorkflowRunCreated`, `WorkflowRunCompleted` [frozen spec, `CreateWebhookRequest.triggers` enum]. There is no event for run archived/deleted, assignment changes, form-field value changes, data-set record changes, or template publication. Weighted push coverage over the fixed critical-plus-important state changes = **45%**. Delivery was verified live (see step 8). Marked partial rather than no because the written `no` condition — "no reliable way to detect the critical state changes" — is demonstrably false: run-created, task-completed and run-completed are all reliably pushed, and documented `status` filtering plus `audit.updatedDate` on every record lets the remaining run-state changes be polled. See disclosed disagreement below.

Score math: earned 3.5 of 4 applicable checks; unrounded fraction = 0.875; category points = 13.125 → **13.1/15**; verification coverage = 4/4 = **100%**

**What this means for you:** This is the strongest part of the API. Everything Process Street does, the API can do — start a checklist, tick tasks off, write form answers, assign people, build and publish templates, manage data sets. Writes are real and were proven on your live account. The weak spot is being told when things change: you get told when a run starts, when a task is ticked, and when a run finishes, and nothing else. There is no "give me everything changed since yesterday" filter, so anything outside those few events means re-reading the whole list and comparing it yourself.

## Category 2: API Design, Reliability, and Operability: 5.0/10
- **C2.1 Modern API conventions: yes** — resource-oriented REST over JSON with standard verbs (62 GET, 35 POST, 29 PUT, 24 DELETE across 82 paths), described by OpenAPI 3.1 [frozen spec]. Confirmed live throughout.
- **C2.2 Consistent typing: no** *(resolved against evidence; see disagreement 1)* — most of the surface is well typed (167 `integer`, 450 `boolean` declarations; `size`/`sizeBytes`/`total` are `integer/int64`; Data Set cells are correctly `oneOf [null, number, string]`, and a Number column written as `42` came back as JSON `42`, not `"42"` [live `GET /data-sets/{id}/records`]). **But the core form-field payload — the primary data path of a workflow product — fails on both directions.** On write, `UpdateMultipleFormFieldValuesRequest.fields[].value` is declared `"type": "string"` and nothing else, so a `Number` form field must be submitted as a string. On read, `SimplifiedFormFieldValue.data` declares **no type at all**, and its description ("a string for `Text`, a number for `Number`, an array of selected option keys for `MultiChoice`") is contradicted by every live read, which returned an object wrapper: `{"data":{"value":"skevin2014@gmail.com"}}`, `{"data":{"value":"2022-09-07T15:00:00.000Z","timeHidden":true}}`, `{"data":{"values":[…]}}`. The same concept — a user-entered value — is therefore typed as a bare `string` on form fields and as a typed union on data-set cells. This satisfies the `no` condition on two counts (core fields stringly typed; types vary across endpoints), and is excluded from `partial`, which requires inconsistencies "confined to non-core fields".
- **C2.3 Structured errors: partial** — a proper structured envelope exists with a stable machine-readable enum of 11 values (`BadRequest, Unauthorized, PaymentRequired, Forbidden, NotFound, MethodNotAllowed, Conflict, PayloadTooLarge, Validation, RateLimited, InternalError`) and correct HTTP status semantics. **The exact limitation:** live testing showed `errorCode` and `requestId` are populated only on handled application errors and are **absent** on the most common failures. `GET /workflows/ZZZ…` → `{"error":"…","errorCode":"NotFound","requestId":"nF8thAn7e7lyvH8iKG9EOg"}`, but `GET /workflows/not-a-real-id` → `{"error":"Path parameter [workflowId] must be a 22-character Muid identifier."}` (400, no code), `?status=Bogus` → 400 no code, `PUT /workflows` → `{"error":"Method Not Allowed"}` (405, no code), `POST /workflows {}` → `{"error":"Field [folderId] is required.; Field [name] is required."}` (400, no code and no `details` object despite the spec documenting field-path details for Validation errors), and `GET /does-not-exist` returned an entire HTML error document embedded inside the JSON `error` string. Error shapes vary across endpoints.
- **C2.4 Duplicate prevention: no** — the spec's own overview states: "For workflow runs, attach a `referenceId` on create — calling `createWorkflowRun` twice with the same `referenceId` will return the existing run instead of creating a duplicate." **`CreateWorkflowRunRequest` contains no `referenceId` property at all** (only `workflowId`, `name`, `dueDate`, `shared`), and on the two other schemas where `referenceId` does appear it means something unrelated — "Version prefix used when version control is enabled". **Live test (controlled live, 2026-08-31):** the identical `POST /workflow-runs` body carrying `referenceId: "apitest-idem-2026-08-31"` was sent twice; both returned 201 and created **two distinct runs**, `gKCX9EluQuU5QbFUG4pDeA` and `v-lFQKfHQhFOQ717RkNCvQ`, confirmed by `GET /workflow-runs/list?workflowId=…` returning 2 records. No idempotency-key header is documented anywhere. `PUT` and `DELETE` are naturally idempotent (verified live: repeat PUT → 200 with unchanged state; repeat DELETE → 404), but the check excludes naturally idempotent operations from earning credit.
- **C2.5 Graceful handling under load: yes** — documented: "If you receive a `429` response, wait for the duration specified in the `Retry-After` header before retrying." Live, **every** response carried machine-readable limit headers: `X-Api-Key-Rate-Limit-Limit: 200`, `X-Api-Key-Rate-Limit-Remaining`, `X-Api-Key-Rate-Limit-Reset`, the IP-level equivalents (`X-Ip-Rate-Limit-Limit: 1000`), and `Retry-After`.
- **C2.6 Pagination for large collections: yes** *(corrected during reconciliation; see disagreement 2)* — documented opaque cursor named `_` plus a `links[]` array carrying a fully-formed `next` href, present on 29 operations, **and a stable ordering guarantee documented per endpoint on 18 list operations**: `/workflows` "sorted by name", `/workflow-runs/list` "sorted by creation date (newest first)", `/users` "sorted by name", `/pages` "sorted by name", `/data-sets` "sorted in order of creation date", `/tasks` "sorted in order of due date", `/comments` "sorted by creation date (newest first)", task and widget lists "ordered by position". Live traversal of `/workflows` completed the whole collection with zero id overlap between pages (page 1 = 20 items → follow `next` → page 2 = 0 items, `next` absent, terminated). Noted but not disqualifying under the check's wording, which requires a next-page token **or** a total count: there is no total-count signal, page size is fixed (`?limit=3` was silently ignored and returned 20), and a `next` link is emitted even when the following page proves empty.
- **C2.7 Bulk or incremental export: partial** — top-level collections can be extracted by cursor-paging list endpoints without per-record calls. **The exact limitation:** there is **no `updated-since`/`modifiedSince` parameter anywhere** (the API's complete query-parameter vocabulary is `_`, `workflowId`, `status`, `type`, `name`, `assigneeEmail`, `workflowRunId`, `taskId`, `createdById`, `fields`, `columns`, `folderId`, `taskType`, `search`, `dueDateFrom`, `dueDateTo`, `snoozeStatus`, `includeCompleted`), no dedicated bulk or async export path, and the operationally valuable data — form-field values — is **not** returned inline on run lists and requires one call per run (`GET /workflow-runs/{id}/form-fields`, verified live). `POST /data-sets/{id}/records/import` is inbound import, not export; Enterprise BI Integrations are a separate Enterprise-only product.
- **C2.8 Webhook security and delivery reliability: partial** — a retry policy is documented ("If you take too long to return a successful response, we will attempt to send the webhook again, for a maximum of 3 tries") and **delivery was observed live**: after `POST /workflow-runs`, the operator-controlled server logged `POST /ps-webhook-test HTTP/1.1" 404 … "ProcessStreet/1.0"` at 19:19:54Z, two seconds after the event. **The exact limitation:** there is no payload signing of any kind — zero occurrences of `signature`, `HMAC` or `secret` in the frozen spec, `CreateWebhookRequest` accepts only `url`, `triggers`, `workflowId`, `taskId` with no secret, and the webhooks help article describes no verification mechanism — and there is no replay or idempotency guidance for consumers.
- **C2.9 Concurrency and conflict control: no** — zero occurrences of `ETag`, `If-Match` or `If-None-Match` in the frozen spec; no version or revision-lock field on mutable resources; and **no operation declares a 409 response** (the only declared response codes across all 150 operations are 200, 201, 204, 400 and `default`). `Conflict` exists solely as an unused value in the error enum, with no documented conflict semantics for any endpoint, and no documented concurrency limits. Concurrent writes are last-write-wins with nothing to detect a lost update.
- **C2.10 Versioning and backward compatibility: partial** — an explicit version identifier exists in the path and the spec (`/api/v1.1`, `info.version: "1.1"`). **The exact limitation:** there is no backward-compatibility policy, no definition of breaking versus non-breaking change, and no deprecation window or notice mechanism — zero occurrences of `deprecat*` or `sunset` in the frozen spec, and none in the help centre.
- **C2.11 Request traceability: partial** *(corrected during reconciliation; see disagreement 3)* — every live response, success and error alike, carried `x-process-street-request-id` (e.g. `ht29sF4qKqvZIq_HMeJMig`), and where a `requestId` body field appeared it held the same value. **The exact limitation:** the two halves never coincide. The header that is present on 100% of responses is **documented nowhere** — `x-process-street-request-id` occurs 0 times in the frozen spec, and only 2 of 150 operations declare response headers at all. The identifier that *is* documented for support use ("Per-request correlation ID. Include this when contacting support so we can find the request in our logs") is the `ErrorInfo.requestId` body field, which appeared on only 1 of the 6 deliberate errors. So there is no single identifier that is both always present and documented as usable with support.
- **C2.12 Service availability and status transparency: partial** — a public status page exists at https://status.process.st/ with per-component status ("Process Street Web Application", "Process Street APIs") and a dated incident-history section. **The exact limitation:** it publishes no uptime percentage and no SLA figures.

Score math: earned 6.0 of 12 applicable checks (3 yes, 6 partial, 3 no; no N-A); unrounded fraction = 0.500000; category points = 5.0 → **5.0/10**; verification coverage = 12/12 = **100%**

**What this means for you:** This is the weakest half of the API and the reason the grade sits where it does. The shape is fine — clean REST, sensible pagination with a documented sort order, and rate-limit headers that tell you exactly when to back off. Three things will cost you real engineering time. First, retry safety is broken: Process Street's own documentation promises that sending the same "start this checklist" twice with the same reference will not create a duplicate, and on your account it created two. Build your own duplicate guard. Second, the form-field data — the actual content of your checklists — is loosely typed in both directions: you must send numbers as text, and the documentation describes the read format incorrectly, so write your integration against what the API actually returns, not against the spec. Third, there is no ETag or version check, so two systems writing the same run will silently overwrite each other.

## Category 3: Access Control and Safe Automation: 3.1/5
- **C3.1 Read-only credentials: no** — no read-only role or credential exists. The four org roles are Admin, Builder, User and Guest, and none is view-only: a User is for "people who only need to work on tasks and workflow runs assigned to them", and even Guests can still act on assigned tasks [https://www.process.st/help/docs/user-permissions/]. Observed in-app 2026-08-31: the graded credential's own profile page reads "API Key #4 — **Admin of RL Property Management**", with all three library folders "Inherited: Edit & View All". The key used for this run therefore had full write authority over the entire organization.
- **C3.2 Scoped credentials: partial** — a genuine fine-grained scoping mechanism is documented: restricted API keys can "scope an API key user's access to specific resources — workflows, pages, forms, files, or data sets". **The exact limitation:** it is Enterprise-only — "Restricted API keys are available on Enterprise plans" — and it was confirmed unavailable on the graded organization. On the Startup org the Users & Guests role filter offers only All Users / Admins / Builders / Users / Guests with **no "API Key Users" option**, API key users do not appear in the member list at all (the org reports "1 ADMIN(S), 0 BUILDER(S), 0 USER(S), 0 GUEST(S)" while four keys exist), so a key's role cannot be changed and every key is an unrestricted org Admin.
- **C3.3 Multiple keys: yes** — four distinct, individually labelled keys were observed on the Integrations page, each with its own label field, masked value, Copy/View controls, access page and delete control, alongside a "New API Key" button [in-app observation, `app.process.st/organizations/manage/integrations`, 2026-08-31].
- **C3.4 Rotation and revocation: yes** — self-serve, no support ticket: each key row carries its own "Delete API Key" control for immediate revocation, keys are freely relabelled, and new keys are created self-serve from the same screen, so rotation is delete-and-reissue by the administrator alone [same observation].
- **C3.5 Test and production isolation: N-A** — no sandbox or separate test environment is offered or evidenced; there is a single production host, `https://public-api.process.st/api/v1.1`. Excluded from the maths.

Score math: earned 2.5 of 4 applicable checks (C3.5 N-A excluded); unrounded fraction = 0.625; category points = 3.125 → **3.1/5**; verification coverage = 4/4 = **100%**

**What this means for you:** This is the weakest category and the one with a real operational risk for you today. On your Startup plan every API key is a full organization administrator — there is no read-only key and no way to limit a key to one workflow or folder. The key you handed me could have deleted every workflow in your account. You do get real control in two respects: you can hold several separate keys, and you can revoke any one of them instantly by yourself, so if a key leaks you can kill it in seconds. The scoping feature that would fix the rest exists, but only on Enterprise. Until then, treat every Process Street key as a master password, give each integration its own key so you can revoke precisely, and never hand one to a third party.

## Category 4: Documentation and AI-Agent Readiness: 3.8/5
- **C4.1 Complete self-serve reference: partial** — the reference is public, requires no login, and is genuinely usable: a rendered reference at `/docs/index.html` (with a `<noscript>` fallback linking the raw spec, so it is readable even without JavaScript), and all 150 operations carry a summary or description. The overview documents authentication, pagination, ID format, date handling, errors, retry semantics and rate limits. **The exact limitation:** worked request examples are missing for most operations — only 42 of 150 have request-body examples, and core write endpoints including `createWorkflowRun` lack one; response examples are largely inferred from schema-level `examples` (570 occurrences across 148 of 358 schemas) rather than given per operation. Separately, and noted here without being scored twice, the overview's idempotency guarantee is factually wrong (graded in C2.4) — a developer or AI agent building from this reference would ship an unsafe integration believing it was protected.
- **C4.2 Reliable machine-consumable integration path: yes** — a complete, maintained, publicly downloadable OpenAPI 3.1 specification suitable for code and tool generation (JSON 1,588,304 bytes; YAML 2,298,618 bytes; 82 paths, 150 operations, 358 schemas), retrievable unauthenticated. Independently, Process Street operates a first-party MCP server at `https://mcp.process.st/` that "supports most Process Street API endpoints as tools", including write operations. Either alone would satisfy this check.
- **C4.3 AI-readable documentation: partial** *(resolved during reconciliation; see disagreement 4)* — `https://www.process.st/llms.txt` (HTTP 200, 8,995 bytes) carries a dedicated "## API & Developer" section, and `https://www.process.st/help/llms.txt` is a 211,972-byte help corpus. **The exact limitation:** both are link indexes with one-line blurbs, not retrievable API content — the root file devotes 5 links to the API, and only about 6 lines of the 212 KB help file touch the API at all; there is no per-endpoint Markdown and no plain-text documentation corpus; `llms-full.txt` returns HTTP 404. The OpenAPI spec and the MCP server are genuinely strong AI-consumption paths, but both are already credited in C4.2, and crediting the same artifacts again here would double-count them against the methodology's own integrity check.
- **C4.4 Kept current: yes** — the first-party release blog carries dated, API-specific entries and is current: "105 New API and MCP Endpoints" (2026-05-21), "Introducing Process Street's MCP Server" (2026-01-27), plus "Form Field APIs Now Support Table Fields (Read and Write)", "Easily Sync External Data Sources into Data Sets with the New CSV Import API Endpoint" and "Upload Files Via the API"; the newest post is 2026-07-15, about six weeks before this run. Noted: the dedicated "New API Endpoints" page is stale at 2025-07-01, and there is no deprecation guidance (graded in C2.10, not here).

Score math: earned 3.0 of 4 applicable checks; unrounded fraction = 0.750; category points = 3.75 → **3.8/5**; verification coverage = 4/4 = **100%**

**What this means for you:** Documentation is the strongest category. The full machine-readable spec is public and free — no login, no sales call — so an AI coding tool can consume the whole API in one file, and Process Street also runs its own MCP server, which means Claude can drive your account directly without you writing an integration at all. That is unusual and valuable. Three cautions: many write endpoints have no worked example, so you will read schemas rather than copy samples; the AI-specific files (`llms.txt`) are only link indexes, so the spec is what an AI tool should actually consume; and the overview contains at least two statements that live testing disproved — the idempotency promise and the form-field read format. Verify behaviour against your own account before trusting a documented guarantee.

## Category 5: Accessibility and Cost: 11.3/15
- **C5.1 Self-serve API key: yes** — an administrator creates a key from the Integrations page with no sales call, support ticket or approval step: "To create an API key you must be an administrator", "you can generate and name a new API key from the integrations page in your organization manager area" [https://www.process.st/help/docs/process-street-api/]. Confirmed in-app: a "New API Key" button sits directly above four existing keys, and the supplied key authenticated live on the first attempt.
- **C5.3 Not commercially gated: partial** — API access itself is included on every tier, not locked behind a premium plan: "Available on All plans" [help/docs/process-street-api/] and "The REST API is available on all plans" [llms.txt]. This was exercised live on a **Startup** organization (Billing page: "T5K Startup - Monthly", Active). **The exact limitation:** the published plan matrix gates meaningful capability by tier — Startup "Public API (50 calls/month)", Pro "Custom no. of API calls/month", Enterprise "Unlimited Public API access" — and two capabilities that materially affect safe automation are Enterprise-only: restricted (scoped) API keys and the BI/Reporting integration. A 50-call monthly allowance would not support any real automation. Observation, recorded for accuracy: roughly 90 calls were made during this run on the Startup plan with no `PaymentRequired` (402) response, so the published cap was not enforced in practice on this organization; the enforced limit observed was a per-key rate limit of 200 requests, not a monthly quota.

Score math: earned 1.5 of 2 applicable checks; unrounded fraction = 0.75; category points = 11.25 → **11.3/15**; verification coverage = 2/2 = **100%**

**What this means for you:** Getting in the door is easy and free — you already have four keys, you made them yourself, and the whole API works on your Startup plan. The catch is on paper rather than in practice: Startup officially allows 50 API calls a month, which would be useless, though nothing enforced that limit during this test. Do not build a business-critical automation on an unenforced allowance without confirming your actual quota with Process Street, because the API does return a specific "payment required" error for plan limits. The scoped-key feature you would want for safety is Enterprise-only.

## Total
- Category points: C1 13.1 + C2 5.0 + C3 3.1 + C4 3.8 + C5 11.3
- Raw (from unrounded category values): 13.125 + 5.0 + 3.125 + 3.75 + 11.25 = **36.25 / 50**
- Normalized before rounding: **72.50 / 100**
- Published numeric score: **73 / 100** (exact half rounded upward, per Step 3)
- Letter grade: **C** (73–76 band)
- Evidence tier: **Fully verified — controlled live**
- Overall verification coverage: **100%** (26 of 26 applicable checks verified; 1 N-A; 0 unverified. Gate: no category Unable to verify — category coverage was 100% in all five; overall ≥ 80% satisfied)
- Partial-result flag: **no**

### Three-run reconciliation (methodology step 12)
Three independent runs graded the identical frozen packet. Unreconciled totals: **75, 72, 70**.
**21 of 26 applicable checks were unanimous.** The five splits were each resolved against the
evidence, not by vote and not by averaging:

| Check | Run A | Run B | Run C | Resolved | Basis |
|---|---|---|---|---|---|
| C2.2 typing | yes | **no** | yes | **no** | Resolved *against* the 2–1 majority. Only one run inspected `UpdateMultipleFormFieldValuesRequest` and `SimplifiedFormFieldValue`; the other two used property-name scans that structurally cannot detect a single `string` type or an untyped field. The majority was a shared blind spot, so the evidence governs. |
| C2.6 pagination | partial | yes | yes | **yes** | Factual. Ordering *is* documented on 18 list operations; the dissenting run had inspected only parameters, not operation descriptions. |
| C2.11 traceability | yes | yes | partial | **partial** | Factual. `x-process-street-request-id` occurs 0 times in the spec; the documented `requestId` field appeared on 1 of 6 errors. No identifier is both always-present and documented. |
| C4.3 AI docs | yes | partial | partial | **partial** | The llms.txt files are index-only for API purposes; the spec and MCP server are already credited in C4.2, and re-crediting them double-counts. |
| C4.4 currency | yes | partial | yes | **yes** | The dissent rested on absent deprecation guidance, which C2.10 explicitly owns ("Do not count the same evidence twice"). On currency alone the feed is dated, first-party and recent. |

### Remaining unresolved disagreement
- **C1.4 partial vs no — the only split that moves the grade, and the largest single effect in the run.** Two runs marked partial, one marked no. All three computed the same underlying facts and a weighted push coverage of 42–46%, below the 0.50 floor of the partial band; no `updated-since` filter exists, so the polling route to partial is unavailable. The partial marks rest on the written `no` condition — "no reliable way to detect the critical state changes" — being demonstrably false, since run-created, task-completed and run-completed are all reliably pushed and delivery was confirmed live. This is a genuine conflict between the check's numeric band and its prose, not a factual dispute, and it is recorded rather than averaged away. **Scoring C1.4 as `no` gives C1 = 11.25, raw 34.375, normalized 68.75 → 69 (D+).** A reader who prefers the strict band reading should use 69.
- Lower-effect sensitivities, all recorded: C4.3 → yes gives **74 (C)**; C2.2 → partial gives **73 (C)**; C3.2 → no gives **72 (C-)**; C2.7 → no gives **72 (C-)**.

## Bottom line for a property manager
Process Street's API can do essentially everything the product can do — start a checklist, tick off tasks, write form answers, assign people, build templates, manage data sets — and I proved the writes on your live account rather than taking the documentation's word for it. The documentation is a real strength: the complete machine-readable spec is public and free, and Process Street runs its own MCP server, so Claude can drive your account with very little custom code. Three things should shape how you use it. First, retry safety is broken: the docs promise that re-sending the same "start this run" request will not create a duplicate, and on your account it created two, so build your own duplicate guard. Second, the documentation is wrong in places that matter — the form-field data format it describes is not the format the API returns — so build against observed behaviour and test each endpoint once yourself. Third, on your Startup plan every API key is a full organization administrator — there is no read-only or workflow-limited key outside Enterprise — so give each integration its own key and revoke precisely when something changes. Process Street is not a PMS, a bank or a trust-accounting system, and it documents no trust, deposit or escrow handling; it is the procedure layer that runs on top of whatever holds your properties, leases and money, and it has a genuine property-management offering — an industry page and eight pre-made templates covering tenant screening, onboarding, inspections and move-in/move-out — but that fit comes from templates and generic form fields, not from any property-specific objects in the API itself.
