{"openapi":"3.1.0","info":{"title":"Mason External API","version":"3-dcbc54383b4fe87a","description":"Read APIs, plus work-order create and update, estimate and invoice approval and rejection, in-house visit appointment booking, moves, and cancellation, vendor contact creation, and updates to the Mason-maintained fields of contacts, units, and properties, for your property management account. Business-data endpoints require an Authorization: Bearer token scoped to your account; write endpoints require a read & write key. Dates are ISO 8601 timestamps. Null is distinct from false, zero, an empty string, and an empty array. V3 uses one effective work-order priority, Mason work-order references named masonWorkOrderId, and visits. Intake metadata is explicitly allowlisted. Other documented stored JSON retains its existing keys; in v3, nested values are returned in their single declared type. Unknown query parameters, and filter values outside a documented enum, return 400. An unsupported HTTP method on a documented path returns 405 with an Allow header listing the supported methods and the standard error body. A path below /{resource}/{id}, such as /scheduling-blocks/{id}/cancel, matches no endpoint and returns 404 with code unknown_resource and the standard error body for every method. This specification describes implemented endpoints only.\n\nAPI keys: create a key in the Mason app under Settings → API access (the API access card at /mason/settings). Any user on the account can create one; there is no separate admin permission. When creating a key you choose a scope: read-only can call the GET business-data endpoints; read & write can also make the documented POST and PATCH writes (work-order create and update, estimate and invoice approval and rejection, vendor contact creation, contact, unit, and property updates, and visit appointment booking, moves, and cancellation). The secret is shown once, at creation, in an on-page banner; Mason stores only its hash and cannot show or recover it afterward, so copy it into a secret manager immediately. To rotate a key, create a new one, switch your integration to it, then revoke the old one; a key is revoked on its own with the Revoke action on the same card. A revoked key is deactivated immediately and its next request returns 401. Each key is scoped to one property management account and authenticates only that account's data. The API access card also shows the account's Production or Test environment; a key created while viewing a Test account is an ordinary key scoped to that test account, subject to the same test-account behavior described elsewhere in this specification — for example, GET /contacts with a test-account key lists the test account's own contacts, while assignment resolves contacts in its parent account. A public, read-only demo API key is also available for trying this API without creating your own key.\n\nErrors and support: every error response is a JSON object with a human-readable error message, a stable machine-readable code, and a requestId. Branch on the HTTP status and code, not on the message text; the Error schema lists every code. Every business-data response, successful or not, carries an X-Mason-Request-Id header, and error bodies repeat it as requestId. You can send your own X-Request-Id to correlate requests with your logs. Contacting support: quote the X-Mason-Request-Id value of the request in question so Mason support can find it.\n\nRecords owned by your property management system: properties, units, residents (tenant contacts), owners, and vendors are mirrored from your connected property management system (AppFolio, RentVine, PropertyWare, Buildium, or Property Meld), which is the system of record for them. This API reads them. Vendors are the one record it can also create, with POST /contacts: when your account is connected to RentVine or AppFolio, Mason creates the vendor there first, as a new vendor record in your property management system, and then saves it in Mason; accounts with no connected system get a vendor in Mason only. Properties, units, residents, and owners cannot be created here. Fields that come from your property management system cannot be changed here, including on vendors: make the change there and Mason picks it up on its next sync. The fields Mason maintains on these records — a contact's preferred contact method, language, communication block (stopAllComms), and internal notes; access details on units and properties; and a property's owner-outreach pause — can be changed with PATCH and are never written to your property management system. For AppFolio, RentVine, and PropertyWare accounts that sync runs nightly, and RentVine vendors also refresh hourly; ask Mason for the schedule that applies to other systems. Mason does not edit the details of existing properties, units, or contacts in your property management system; it creates a new vendor or owner in AppFolio or RentVine only when your team asks, or authorizes, Mason to add one. At your team's request, Mason can also attach files to property records in your property management system, and remove a specific file from a PropertyWare property. Accounts without any connected system maintain these records in the Mason app; accounts on other connected systems sync on their own schedule.\n\nSyncing data: to keep a local copy of a resource in sync, record T1, the current time, before you start a run. List the resource with updatedAfter=T0 where the resource exposes it, otherwise createdAfter=T0; a run with no T0 is a full first load, which is the same traversal with no lower bound — there is no separate bulk-export job. Follow pagination.nextCursor with the same filters until pagination.hasMore is false, then store T1 minus an overlap window as the next run's T0; 15 minutes is a reasonable default. Dedupe incoming records by id, since records inside the overlap window are returned again.\n\nSize the overlap to how long each resource keeps changing after its createdAt: calls, emails, text-messages, and scheduling-blocks have no updatedAt column, so createdAfter is their only incremental key. For calls, callStatus, endedAt, transcript, summary, recordingUrl, and masonWorkOrderId/relatedWorkOrderIds are finalized once the call ends and Mason finishes post-call processing. For emails and text-messages, masonWorkOrderId, relatedWorkOrderIds, senderRole, and, for emails, metadata are assigned when Mason processes the message, normally within minutes of createdAt. For scheduling-blocks, start, end, blockType, notes, and tenantConfirmationStatus change later, potentially long after createdAt, when an appointment is moved, reassigned, cancelled, or has its tenant confirmation status updated by a dispatcher; such a change is normally also recorded on the owning work order's GET /work-order-activity-logs, with eventType visit_rescheduled for a move, visit_reassigned for a technician reassignment, visit_unscheduled (portal_visit_unscheduled from the tech or vendor portal) for a cancellation, and tenant_confirmation_status_updated for a dispatcher-recorded tenant confirmation change, so after on that endpoint is an incremental key for catching a scheduling-block change after the block's own creation. As with GET /work-order-activity-logs generally, this is a best-effort change signal with no complete-history guarantee, not proof a scheduling-block field never changed, so also periodically re-read scheduling-blocks for open work orders rather than relying on activity events alone. contacts, estimates, invoices, properties, units, visits, and work-orders expose updatedAt, which advances whenever the record's own fields change; for these seven, updatedAfter is a reliable incremental key on its own, using the same overlap window to cover a write that commits after T1 was recorded.\n\nVersioning and compatibility: each major version has its own path (/api/external/v1, /v2, and /v3). Within a version Mason makes only non-breaking changes: new endpoints, new optional request parameters and body fields, new response fields, and new enum values, including new error codes. Clients must ignore response fields they do not recognize and must handle enum values they do not recognize. Breaking changes, such as removing or renaming a field, changing a field's type, adding a required parameter or body field, or rejecting requests that are accepted today, ship only in a new path version. Deprecations are announced in the changelog (GET /api/external/v3/changelog) at least 6 months before removal, and responses from a deprecated version carry Deprecation and Sunset headers. V1 and v2 remain available for existing integrations; no deprecation or sunset date is set for either. info.version identifies the exact revision of this specification, and each changelog entry names the revision that introduced it. Narrowing a field's declared type to one of the types it already permitted (for example number|string to number, with the same values) is a tightening, not a breaking change, and is listed under Changed in the changelog."},"servers":[{"url":"https://mason.enduring-labs.com/api/external/v3","description":"Production Mason External API v3."}],"security":[{"bearerAuth":[]}],"tags":[{"name":"units","description":"Current stored units, authorized through their owning property. Vacancy and inspection fields do not provide complete historical cycles or a dated door-count denominator. Units are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. This API does not create units. PATCH /units/{id} changes only the Mason-maintained access field, which Mason does not write to your property management system; every other field is read-only here and changes only in your property management system."},{"name":"emails","description":"Stored email content and sender provenance for your account. No trimming, classification, ingestion, or sending occurs on read. Work-order filters match the primary link only."},{"name":"estimates","description":"Stored vendor estimates and recorded approval decisions. Money is cents. Legacy PM-prefixed decision fields can represent owner decisions; ownerMessageDrafted does not prove delivery."},{"name":"work-order-activity-logs","description":"Allowlisted stored business events, authorized through the owning work order. Unsupported event types/versions and malformed selected payloads are excluded before pagination and from detail reads. No complete-history guarantee; absence is not proof an action never occurred. Sorts by timestamp and ID descending."},{"name":"work-orders","description":"Maintenance work orders belonging to your property management account. Priority describes office attention; isEmergency indicates an emergency. Returned values reflect current stored state, not a historical snapshot."},{"name":"calls","description":"Recorded phone calls scoped to your property management account. Call content and recording availability depend on the stored record."},{"name":"text-messages","description":"Stored inbound and outbound text messages for your property management account. Work-order filtering matches the primary linked work order."},{"name":"invoices","description":"Stored invoices, matching results, and review/billing state. Top-level monetary amounts are integer cents. Nested document data is returned as stored, except that line-item quantities and amounts, matched-record identifiers, and party addresses are returned in their documented types; a stored value that cannot be read as that type is null."},{"name":"contacts","description":"People and businesses in your property management account. Hydrate contact references with a detail request or the id/ids filters, even when the contact predates your incremental sync window. Tenant (resident), owner, and vendor contacts are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. Technician, property-manager, emergency, and unidentified contacts are maintained in Mason. POST /contacts creates vendor contacts only: in RentVine or AppFolio first when your account is connected to one, otherwise in Mason alone. PATCH /contacts/{id} changes only the Mason-maintained fields preferredContactMethod, language, stopAllComms, and notes, which Mason does not write to your property management system; every other field is read-only here, and fields your property management system provides change only there."},{"name":"visits","description":"Maintenance visit records. Assigned technicians describe assignment, not completed labor. Nested JSON is returned as stored; changes to related records do not necessarily update this record timestamp."},{"name":"properties","description":"Properties associated with your account, including stored address, ownership, and provider details. No geocoding or owner lookup runs as part of this read. Properties are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. This API does not create properties. PATCH /properties/{id} changes only the Mason-maintained fields access and pauseOwnerOutreach, which Mason does not write to your property management system; every other field is read-only here and changes only in your property management system."},{"name":"scheduling-blocks","description":"Stored availability and appointment blocks. blockType=confirmed identifies a confirmed work window. A confirmed block and tenantConfirmationStatus are distinct facts. Range endpoints can be null for unbounded windows."},{"name":"on-call-coverage","description":"Recorded effective on-call coverage for a bounded time range."},{"name":"documentation","description":"Public machine-readable API reference."}],"paths":{"/work-orders":{"get":{"tags":["work-orders"],"operationId":"listWorkOrder","summary":"List work-orders","description":"Maintenance work orders belonging to your property management account. Priority describes office attention; isEmergency indicates an emergency. Returned values reflect current stored state, not a historical snapshot.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Exact match on status. Stored work-order lifecycle status. Current values: created, reviewed, estimated, work_in_progress, duplicate, cancelled, not_handled_by_mason, work_done, closed. Historical values are returned unchanged. This is not visit or message-delivery status.","schema":{"type":"string","description":"Exact match on status. Stored work-order lifecycle status. Current values: created, reviewed, estimated, work_in_progress, duplicate, cancelled, not_handled_by_mason, work_done, closed. Historical values are returned unchanged. This is not visit or message-delivery status."}},{"name":"workOrderType","in":"query","required":false,"description":"Exact match on workOrderType. Stored work category: reactive, reactive:recall, preventative, turn, recurring, misc, inspection, or an inspection subtype such as inspection:annual, inspection:move_in, inspection:move_out, inspection:pre_move_out, inspection:onboarding, inspection:semi_annual, or inspection:drive_by. Legacy values are returned unchanged.","schema":{"type":"string","description":"Exact match on workOrderType. Stored work category: reactive, reactive:recall, preventative, turn, recurring, misc, inspection, or an inspection subtype such as inspection:annual, inspection:move_in, inspection:move_out, inspection:pre_move_out, inspection:onboarding, inspection:semi_annual, or inspection:drive_by. Legacy values are returned unchanged."}},{"name":"source","in":"query","required":false,"description":"Exact match on source. Stored intake channel, commonly pms:portal, pms:text, pms:email, pms:call, pms:system, mason:portal, mason:text, mason:email, mason:call, mason:system, or mason:recurring. It describes the origin/channel, not the requester identity. Legacy values are returned unchanged.","schema":{"type":"string","description":"Exact match on source. Stored intake channel, commonly pms:portal, pms:text, pms:email, pms:call, pms:system, mason:portal, mason:text, mason:email, mason:call, mason:system, or mason:recurring. It describes the origin/channel, not the requester identity. Legacy values are returned unchanged."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"updatedAfter","in":"query","required":false,"description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"updatedBefore","in":"query","required":false,"description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"propertyId","in":"query","required":false,"description":"Exact match on propertyId. Linked Mason property ID. Resolve using GET /properties/{id}.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on propertyId. Linked Mason property ID. Resolve using GET /properties/{id}."}},{"name":"unitId","in":"query","required":false,"description":"Exact match on unitId. Linked Mason unit ID, when present. Resolve using GET /units/{id}.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on unitId. Linked Mason unit ID, when present. Resolve using GET /units/{id}."}},{"name":"assignedUser","in":"query","required":false,"description":"Match work orders whose stored assignedUsers array contains this exact email address.","schema":{"type":"string","description":"Match work orders whose stored assignedUsers array contains this exact email address."}},{"name":"priority","in":"query","required":false,"description":"Exact match on priority. Effective attention priority. Uses the explicit user override when present, otherwise the assessment. Null means no recognized priority is recorded. Other values return 400.","schema":{"type":"string","enum":["low","normal","urgent"],"description":"Exact match on priority. Effective attention priority. Uses the explicit user override when present, otherwise the assessment. Null means no recognized priority is recorded. Other values return 400."}},{"name":"isEmergency","in":"query","required":false,"description":"Exact match on isEmergency. Whether the work order is currently marked as an emergency.","schema":{"type":"boolean","description":"Exact match on isEmergency. Whether the work order is currently marked as an emergency."}},{"name":"requesterContactId","in":"query","required":false,"description":"Exact match on requesterContactId. Mason contact ID of the recorded requester; null means unresolved or not recorded.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on requesterContactId. Mason contact ID of the recorded requester; null means unresolved or not recorded."}},{"name":"vendorContactId","in":"query","required":false,"description":"Exact match on vendorContactId. Assigned vendor or in-house technician Mason contact ID. Resolve using GET /contacts/{id}; contactType may be vendor or tech.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on vendorContactId. Assigned vendor or in-house technician Mason contact ID. Resolve using GET /contacts/{id}; contactType may be vendor or tech."}}],"responses":{"200":{"description":"One page of work-orders visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching work-orders records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/WorkOrder"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"11111111-1111-4111-8111-111111111111","description":"Kitchen faucet is leaking under the sink.","status":"reviewed","propertyAddress":"123 Example St, Springfield, IL 62701","source":"mason:portal","workOrderType":"reactive","friendlyId":"WO-1042","isEmergency":false,"hasEntryPermission":true,"propertyId":"22222222-2222-4222-8222-222222222222","unitId":"33333333-3333-4333-8333-333333333333","tenantContactId":"44444444-4444-4444-8444-444444444444","vendorContactId":null,"intakeMetadata":{"reportedByRole":"tenant"},"priority":"normal","createdAt":"2026-09-21T15:04:05.000Z","updatedAt":"2026-09-21T15:30:00.000Z","assignedUsers":["manager@example.com"],"requesterContactId":"44444444-4444-4444-8444-444444444444","scopeOfWork":"Replace the kitchen faucet cartridge and check the supply lines for leaks.","entryPermissionConditions":"Call 30 minutes before arriving; dog on site.","handledBy":"mason","workOrderReview":{"vendorType":"plumbing","projectTicketCategory":null},"completionAnalysis":null,"vendorWorkOrderRequest":null,"relationships":[],"pms":{"system":"appfolio","profileId":"12121212-1212-4121-8121-121212121212","workOrderId":"10042","workOrderNumber":"1042-1"}}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"post":{"tags":["work-orders"],"operationId":"createWorkOrder","summary":"Create a work order","description":"Creates a work order the same way a property manager does in Mason. It is also created in your connected property management system, and Mason starts its review, which can continue into vendor outreach and dispatch under your account's workflow settings. Requires a read & write API key. Send a unique Idempotency-Key per work order; a retry with the same key and body returns the original response instead of creating a duplicate.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Client-chosen key, unique per work order you intend to create (for example a UUID or your own record ID). 1-255 printable ASCII characters. Reusing it with a different body returns 422.","schema":{"type":"string","minLength":1,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkOrderRequest"},"examples":{"tenantRequest":{"summary":"A tenant-reported repair","value":{"description":"Kitchen faucet is leaking under the sink.","propertyId":"22222222-2222-4222-8222-222222222222","unitId":"33333333-3333-4333-8333-333333333333","tenantContactId":"44444444-4444-4444-8444-444444444444","workOrderType":"reactive","source":"mason:text"}},"minimal":{"summary":"Only the required fields","value":{"description":"Replace the hallway smoke detector battery.","propertyId":"22222222-2222-4222-8222-222222222222"}}}}}},"responses":{"201":{"description":"The created work order. A replayed response carries the header Idempotent-Replayed: true.","content":{"application/json":{"schema":{"type":"object","description":"Created work-order response.","required":["data","pmsCreateError"],"additionalProperties":false,"properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/WorkOrder"},{"type":"object","description":"Returned only when the created work order could not be read back; fetch it by id.","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid","description":"Mason UUID of the created work order."}}}]},"pmsCreateError":{"type":["string","null"],"description":"Why the work order could not be created in the property management system, or null. The Mason work order exists either way."}}},"examples":{"created":{"summary":"Created","value":{"data":{"id":"11111111-1111-4111-8111-111111111111","description":"Kitchen faucet is leaking under the sink.","status":"reviewed","propertyAddress":"123 Example St, Springfield, IL 62701","source":"mason:portal","workOrderType":"reactive","friendlyId":"WO-1042","isEmergency":false,"hasEntryPermission":true,"propertyId":"22222222-2222-4222-8222-222222222222","unitId":"33333333-3333-4333-8333-333333333333","tenantContactId":"44444444-4444-4444-8444-444444444444","vendorContactId":null,"intakeMetadata":{"reportedByRole":"tenant"},"priority":"normal","createdAt":"2026-09-21T15:04:05.000Z","updatedAt":"2026-09-21T15:30:00.000Z","assignedUsers":["manager@example.com"],"requesterContactId":"44444444-4444-4444-8444-444444444444","scopeOfWork":"Replace the kitchen faucet cartridge and check the supply lines for leaks.","entryPermissionConditions":"Call 30 minutes before arriving; dog on site.","handledBy":"mason","workOrderReview":{"vendorType":"plumbing","projectTicketCategory":null},"completionAnalysis":null,"vendorWorkOrderRequest":null,"relationships":[],"pms":{"system":"appfolio","profileId":"12121212-1212-4121-8121-121212121212","workOrderId":"10042","workOrderNumber":"1042-1"}},"pmsCreateError":null}},"pmsCreateFailed":{"summary":"Created in Mason; the property management system create failed","value":{"data":{"id":"11111111-1111-4111-8111-111111111111","description":"Kitchen faucet is leaking under the sink.","status":"reviewed","propertyAddress":"123 Example St, Springfield, IL 62701","source":"mason:portal","workOrderType":"reactive","friendlyId":"WO-1042","isEmergency":false,"hasEntryPermission":true,"propertyId":"22222222-2222-4222-8222-222222222222","unitId":"33333333-3333-4333-8333-333333333333","tenantContactId":"44444444-4444-4444-8444-444444444444","vendorContactId":null,"intakeMetadata":{"reportedByRole":"tenant"},"priority":"normal","createdAt":"2026-09-21T15:04:05.000Z","updatedAt":"2026-09-21T15:30:00.000Z","assignedUsers":["manager@example.com"],"requesterContactId":"44444444-4444-4444-8444-444444444444","scopeOfWork":"Replace the kitchen faucet cartridge and check the supply lines for leaks.","entryPermissionConditions":"Call 30 minutes before arriving; dog on site.","handledBy":"mason","workOrderReview":{"vendorType":"plumbing","projectTicketCategory":null},"completionAnalysis":null,"vendorWorkOrderRequest":null,"relationships":[],"pms":null},"pmsCreateError":"AppFolio rejected the work order: unit is inactive."}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Invalid JSON, unknown or invalid fields, a missing Idempotency-Key, or a property, unit, or tenant that does not match this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalidBody":{"summary":"Invalid field","value":{"error":"Invalid request body. propertyId: Invalid UUID","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"keyRequired":{"summary":"Missing Idempotency-Key","value":{"error":"Idempotency-Key header is required: 1-255 printable ASCII characters, unique per write.","code":"idempotency_key_required","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"propertyMismatch":{"summary":"Property not in this account","value":{"error":"Selected property was not found for this property manager","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only (code insufficient_scope), or the account is not live in Mason yet (code account_not_live). Work-order creation is part of every Mason plan at no separate charge. It becomes available once the account is live in Mason; until then this endpoint returns 403 with code account_not_live.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"accountNotLive":{"summary":"Account not live in Mason yet","value":{"error":"Work-order creation is available once your account is live in Mason. It is part of every Mason plan at no separate charge; contact your Mason team to finish going live.","code":"account_not_live","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"409":{"description":"A request with this Idempotency-Key is still in progress, or an earlier one did not finish.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"inProgress":{"summary":"Same Idempotency-Key still in progress","value":{"error":"A request with this Idempotency-Key is still in progress.","code":"idempotency_in_progress","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"unfinished":{"summary":"Same Idempotency-Key did not finish","value":{"error":"A previous request with this Idempotency-Key did not finish. Check whether it took effect before retrying with a new key.","code":"idempotency_request_unfinished","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"422":{"description":"This Idempotency-Key was already used with a different request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"keyReused":{"summary":"Idempotency-Key reused with a different body","value":{"error":"This Idempotency-Key was already used with a different request.","code":"idempotency_key_reused","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request failed and may have partially taken effect: the work order may exist in Mason or only in your property management system. The same Idempotency-Key replays this failure; check both before retrying with a new key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"writeFailed":{"summary":"Write may have partially taken effect","value":{"error":"The request failed and may have partially taken effect, in Mason or in your property management system. Check both before retrying with a new Idempotency-Key.","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/work-orders/{id}":{"get":{"tags":["work-orders"],"operationId":"getWorkOrder","summary":"Get one work-orders record","description":"Maintenance work orders belonging to your property management account. Priority describes office attention; isEmergency indicates an emergency. Returned values reflect current stored state, not a historical snapshot.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404. The ETag response header identifies this version of the work order; send it as If-Match when updating it.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/WorkOrder"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"11111111-1111-4111-8111-111111111111","description":"Kitchen faucet is leaking under the sink.","status":"reviewed","propertyAddress":"123 Example St, Springfield, IL 62701","source":"mason:portal","workOrderType":"reactive","friendlyId":"WO-1042","isEmergency":false,"hasEntryPermission":true,"propertyId":"22222222-2222-4222-8222-222222222222","unitId":"33333333-3333-4333-8333-333333333333","tenantContactId":"44444444-4444-4444-8444-444444444444","vendorContactId":null,"intakeMetadata":{"reportedByRole":"tenant"},"priority":"normal","createdAt":"2026-09-21T15:04:05.000Z","updatedAt":"2026-09-21T15:30:00.000Z","assignedUsers":["manager@example.com"],"requesterContactId":"44444444-4444-4444-8444-444444444444","scopeOfWork":"Replace the kitchen faucet cartridge and check the supply lines for leaks.","entryPermissionConditions":"Call 30 minutes before arriving; dog on site.","handledBy":"mason","workOrderReview":{"vendorType":"plumbing","projectTicketCategory":null},"completionAnalysis":null,"vendorWorkOrderRequest":null,"relationships":[],"pms":{"system":"appfolio","profileId":"12121212-1212-4121-8121-121212121212","workOrderId":"10042","workOrderNumber":"1042-1"}}}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the work order, derived from its updatedAt. Send it as If-Match on PATCH /work-orders/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-21T15:30:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"patch":{"tags":["work-orders"],"operationId":"updateWorkOrder","summary":"Update a work order","description":"Changes the listed fields as a property manager would in Mason, recorded in the activity log as this API key. Description, status, work-order type, and assignment changes are synchronized to your property management system. An assignment dispatches the vendor or in-house technician through the same dispatch path as a manual dispatch from the Mason app, with the differences listed below. Requires a read & write API key.\n\nDifferences from a manual dispatch in the app:\n\n- For vendor assignments, an open emergency escalation is not acknowledged; the on-call chain keeps running until the vendor accepts.\n- No not-to-exceed amount is sent; the property's maintenance limit applies where one is configured.\n- No tenant or owner dispatch notification is sent, except that a technician assignment texts the tenant a scheduling link when the account has tenant scheduling enabled.\n- In-house department vendors are refused; assign one of their technicians with technicianContactId.\n- The vendor-override feedback the app asks for is not required, and the channel used is not saved as the vendor's preferred contact method.\n- Activity summaries and dispatch analytics record the assignment as a manual dispatch (source manual_dispatch), attributed to this API key.\n- A replaced vendor's cancellation says it was replaced \"via dispatch modal\" on a vendor assignment and \"via the Mason API\" on a technician assignment.\n- For vendor assignments, dispatches are serialized so two identical requests cannot both create a visit; technician assignments have no dispatch lock in the app either.\n- A technician whose previous dispatch on this work order was denied (status denied) is refused with 409, where the app allows re-dispatch; re-dispatch that technician from Mason.\n- With a test-account key, GET /contacts lists the test account's own contacts, but assignment resolves contacts in its parent account.\n\nOptimistic concurrency: this endpoint and GET /work-orders/{id} return an ETag derived from the work order's updatedAt. Sending it as If-Match is strongly recommended: when the work order changed since that read, the request returns 412 before any field is applied. updatedAt advances when the work order's own fields change, including changes made by Mason's own automation and property management system sync, so a 412 can occur without another API client. Changes to related records such as visits, calls, and invoices do not advance it. The check is not a lock: a change made while this request is being applied is not detected.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the work-order id field.","schema":{"type":"string","format":"uuid"}},{"name":"If-Match","in":"header","required":false,"description":"Strongly recommended. The ETag from your latest read of this work order; a comma-separated list is accepted. When none matches the current ETag, the request returns 412 and applies nothing. * matches any existing work order. When omitted, the changes apply regardless of intervening updates.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkOrderRequest"},"examples":{"escalate":{"summary":"Raise priority and mark an emergency","value":{"priority":"urgent","isEmergency":true}},"assignVendor":{"summary":"Assign a vendor","value":{"assignment":{"vendorContactId":"55555555-5555-4555-8555-555555555555"}}},"assignTechnician":{"summary":"Assign an in-house technician","value":{"assignment":{"technicianContactId":"66666666-6666-4666-8666-666666666666"}}},"close":{"summary":"Close with a note","value":{"status":"closed","statusNote":"Repair confirmed by the tenant."}}}}}},"responses":{"200":{"description":"The work order after every requested change. pmsAssignmentError is included only when a technician assignment was applied in Mason but rejected by the property management system.","headers":{"ETag":{"description":"Strong validator for this version of the work order, derived from its updatedAt. Send it as If-Match on PATCH /work-orders/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-22T09:00:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/WorkOrder"},"pmsAssignmentError":{"type":"string","description":"Present only when a technician assignment in this request was applied in Mason but the property management system rejected it. The Mason assignment stands; update the property management system yourself."}}},"examples":{"updated":{"summary":"Updated","value":{"data":{"id":"11111111-1111-4111-8111-111111111111","description":"Kitchen faucet is leaking under the sink.","status":"reviewed","propertyAddress":"123 Example St, Springfield, IL 62701","source":"mason:portal","workOrderType":"reactive","friendlyId":"WO-1042","isEmergency":true,"hasEntryPermission":true,"propertyId":"22222222-2222-4222-8222-222222222222","unitId":"33333333-3333-4333-8333-333333333333","tenantContactId":"44444444-4444-4444-8444-444444444444","vendorContactId":null,"intakeMetadata":{"reportedByRole":"tenant"},"priority":"urgent","createdAt":"2026-09-21T15:04:05.000Z","updatedAt":"2026-09-22T09:00:00.000Z","assignedUsers":["manager@example.com"],"requesterContactId":"44444444-4444-4444-8444-444444444444","scopeOfWork":"Replace the kitchen faucet cartridge and check the supply lines for leaks.","entryPermissionConditions":"Call 30 minutes before arriving; dog on site.","handledBy":"mason","workOrderReview":{"vendorType":"plumbing","projectTicketCategory":null},"completionAnalysis":null,"vendorWorkOrderRequest":null,"relationships":[],"pms":{"system":"appfolio","profileId":"12121212-1212-4121-8121-121212121212","workOrderId":"10042","workOrderNumber":"1042-1"}}}}}}}},"400":{"description":"Invalid JSON or fields, no updatable field, an assignment contact that is not an active vendor or technician in this account or is an in-house department, or a change Mason rejected. A rejected change reports the field and any fields already applied.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/WorkOrderUpdateError"}]},"examples":{"invalidBody":{"summary":"No updatable field","value":{"error":"Invalid request body. Provide at least one of: workOrderType, description, priority, isEmergency, assignment, status","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"notAVendor":{"summary":"Assignment contact is not a vendor","value":{"error":"vendorContactId must be the ID of a vendor contact in this account.","code":"invalid_body","field":"assignment","appliedFields":["priority"],"requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No work order exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/WorkOrderUpdateError"}]},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"409":{"description":"The assignment conflicts with the current dispatch state: the vendor is already assigned to or was already dispatched on this work order, the technician is already assigned to it, the same assignment was already made, another vendor dispatch is in progress or has an unconfirmed outcome, Mason is stopped on this work order, or the scope changed and must be reviewed in Mason. Nothing was dispatched; fields listed in appliedFields were already applied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkOrderUpdateError"},"examples":{"alreadyAssigned":{"summary":"Vendor already assigned","value":{"error":"This vendor is already assigned to or was already dispatched on this work order. Send another dispatch to the same vendor from Mason.","code":"conflict","field":"assignment","appliedFields":[],"requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"412":{"description":"If-Match did not match the current ETag. No field was applied. The ETag header carries the current version; read the work order again before retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"staleEtag":{"summary":"The work order changed since it was read","value":{"error":"The work order changed since the If-Match version was read. Fetch it again and retry with the new ETag.","code":"precondition_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the work order, derived from its updatedAt. Send it as If-Match on PATCH /work-orders/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-21T15:30:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"502":{"description":"The property management system rejected a work-order type change; a status change out of duplicate, cancelled, or not handled by Mason that the property management system could not reopen, in which case the status is unchanged; a vendor dispatch was not sent, for example because the property management system rejected the vendor assignment or the vendor has no usable email or phone; or the assignment failed unexpectedly and may have partially taken effect, in which case check the work order in Mason before assigning again. A technician assignment the property management system rejects returns 200 with pmsAssignmentError instead. The error explains why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkOrderUpdateError"},"examples":{"dispatchFailed":{"summary":"Dispatch could not be completed","value":{"error":"Failed to assign vendor in PMS: vendor inactive","code":"dispatch_failed","field":"assignment","appliedFields":["priority","isEmergency"],"requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"pmsRejected":{"summary":"Property management system rejected a type change","value":{"error":"Could not change the work order type because AppFolio could not be updated. Please try again.","code":"pms_write_failed","field":"workOrderType","appliedFields":[],"requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/calls":{"get":{"tags":["calls"],"operationId":"listCall","summary":"List calls","description":"Recorded phone calls scoped to your property management account. Call content and recording availability depend on the stored record.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"callStatus","in":"query","required":false,"description":"Exact match on callStatus. Stored call outcome, such as completed, failed, busy, or no-answer.","schema":{"type":"string","description":"Exact match on callStatus. Stored call outcome, such as completed, failed, busy, or no-answer."}},{"name":"callerRole","in":"query","required":false,"description":"Exact match on callerRole. Recorded role of the other party, such as tenant, vendor, or property_manager. Legacy roles may occur.","schema":{"type":"string","description":"Exact match on callerRole. Recorded role of the other party, such as tenant, vendor, or property_manager. Legacy roles may occur."}},{"name":"inBound","in":"query","required":false,"description":"Exact match on inBound. True for an incoming call; false for an outgoing call.","schema":{"type":"boolean","description":"Exact match on inBound. True for an incoming call; false for an outgoing call."}},{"name":"masonWorkOrderId","in":"query","required":false,"description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked."}},{"name":"contactId","in":"query","required":false,"description":"Exact match on masonContactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonContactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}}],"responses":{"200":{"description":"One page of calls visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching calls records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/Call"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb","phoneNumber":"+15555550123","summary":"Tenant reported a leaking kitchen faucet and asked for a repair.","transcript":"Tenant: Hi, my kitchen faucet is leaking under the sink.\nMason: Thanks, I have opened a work order for you.","callDuration":184,"recordingUrl":"https://recordings.example.com/calls/example-1042.mp3","inBound":true,"callStatus":"completed","callerRole":"tenant","callType":"work_order_creation","requiresAction":false,"masonWorkOrderId":"11111111-1111-4111-8111-111111111111","masonContactId":"44444444-4444-4444-8444-444444444444","createdAt":"2026-09-21T15:00:00.000Z","endedAt":"2026-09-21T15:03:04.000Z","callSid":"CA00000000000000000000000000example","relatedWorkOrderIds":[]}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/calls/{id}":{"get":{"tags":["calls"],"operationId":"getCall","summary":"Get one calls record","description":"Recorded phone calls scoped to your property management account. Call content and recording availability depend on the stored record.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Call"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb","phoneNumber":"+15555550123","summary":"Tenant reported a leaking kitchen faucet and asked for a repair.","transcript":"Tenant: Hi, my kitchen faucet is leaking under the sink.\nMason: Thanks, I have opened a work order for you.","callDuration":184,"recordingUrl":"https://recordings.example.com/calls/example-1042.mp3","inBound":true,"callStatus":"completed","callerRole":"tenant","callType":"work_order_creation","requiresAction":false,"masonWorkOrderId":"11111111-1111-4111-8111-111111111111","masonContactId":"44444444-4444-4444-8444-444444444444","createdAt":"2026-09-21T15:00:00.000Z","endedAt":"2026-09-21T15:03:04.000Z","callSid":"CA00000000000000000000000000example","relatedWorkOrderIds":[]}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/text-messages":{"get":{"tags":["text-messages"],"operationId":"listTextMessage","summary":"List text-messages","description":"Stored inbound and outbound text messages for your property management account. Work-order filtering matches the primary linked work order.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"senderRole","in":"query","required":false,"description":"Exact match on senderRole. Recorded sender role, such as tenant, vendor, owner, tech, or property_manager. Legacy roles may occur.","schema":{"type":"string","description":"Exact match on senderRole. Recorded sender role, such as tenant, vendor, owner, tech, or property_manager. Legacy roles may occur."}},{"name":"masonWorkOrderId","in":"query","required":false,"description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked."}},{"name":"contactId","in":"query","required":false,"description":"Exact match on masonContactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonContactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"source","in":"query","required":false,"description":"Exact match on source. Stored communication origin label, returned verbatim. It is attribution, not proof of delivery or a newly inferred classification.","schema":{"type":"string","description":"Exact match on source. Stored communication origin label, returned verbatim. It is attribution, not proof of delivery or a newly inferred classification."}},{"name":"provider","in":"query","required":false,"description":"Exact match on provider. Recorded communication transport provider, returned verbatim; null means none was recorded.","schema":{"type":"string","description":"Exact match on provider. Recorded communication transport provider, returned verbatim; null means none was recorded."}}],"responses":{"200":{"description":"One page of text-messages visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching text-messages records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/TextMessage"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"cccccccc-cccc-4ccc-8ccc-cccccccccccc","phoneNumber":"+15555550123","message":"A plumber will contact you today to schedule the faucet repair.","mediaUrls":null,"inBound":false,"senderRole":"property_manager","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","masonContactId":"44444444-4444-4444-8444-444444444444","fromNumber":"+15555550100","toNumber":"+15555550123","createdAt":"2026-09-21T15:10:00.000Z","source":"mason","provider":"twilio","messageSid":"SM00000000000000000000000000example","conversationSid":null,"relatedWorkOrderIds":null,"metadata":null}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/text-messages/{id}":{"get":{"tags":["text-messages"],"operationId":"getTextMessage","summary":"Get one text-messages record","description":"Stored inbound and outbound text messages for your property management account. Work-order filtering matches the primary linked work order.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/TextMessage"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"cccccccc-cccc-4ccc-8ccc-cccccccccccc","phoneNumber":"+15555550123","message":"A plumber will contact you today to schedule the faucet repair.","mediaUrls":null,"inBound":false,"senderRole":"property_manager","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","masonContactId":"44444444-4444-4444-8444-444444444444","fromNumber":"+15555550100","toNumber":"+15555550123","createdAt":"2026-09-21T15:10:00.000Z","source":"mason","provider":"twilio","messageSid":"SM00000000000000000000000000example","conversationSid":null,"relatedWorkOrderIds":null,"metadata":null}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/invoices":{"get":{"tags":["invoices"],"operationId":"listInvoice","summary":"List invoices","description":"Stored invoices, matching results, and review/billing state. Top-level monetary amounts are integer cents. Nested document data is returned as stored, except that line-item quantities and amounts, matched-record identifiers, and party addresses are returned in their documented types; a stored value that cannot be read as that type is null.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Exact match on status. Stored invoice processing status, such as pending, processed, incomplete, not_invoice, reprocessing, failed, failed_with_partial_data, or no_pdf_attachments.","schema":{"type":"string","description":"Exact match on status. Stored invoice processing status, such as pending, processed, incomplete, not_invoice, reprocessing, failed, failed_with_partial_data, or no_pdf_attachments."}},{"name":"confidence","in":"query","required":false,"description":"Exact match on confidence. Stored extraction confidence or processing classification. Common values include high, medium, low, failed, failed_with_partial_data, and no_pdf_attachments.","schema":{"type":"string","description":"Exact match on confidence. Stored extraction confidence or processing classification. Common values include high, medium, low, failed, failed_with_partial_data, and no_pdf_attachments."}},{"name":"isInvoice","in":"query","required":false,"description":"Exact match on isInvoice. Whether this record is classified as an invoice.","schema":{"type":"boolean","description":"Exact match on isInvoice. Whether this record is classified as an invoice."}},{"name":"isRecurring","in":"query","required":false,"description":"Exact match on isRecurring. Whether the invoice was classified as recurring.","schema":{"type":"boolean","description":"Exact match on isRecurring. Whether the invoice was classified as recurring."}},{"name":"reviewed","in":"query","required":false,"description":"Exact match on reviewed. Whether the invoice has been marked reviewed by the office/accounting process.","schema":{"type":"boolean","description":"Exact match on reviewed. Whether the invoice has been marked reviewed by the office/accounting process."}},{"name":"reviewReason","in":"query","required":false,"description":"Exact match on reviewReason. Recorded review disposition, commonly bill_created, completed_outside_mason, duplicate, not_an_invoice, or archived.","schema":{"type":"string","description":"Exact match on reviewReason. Recorded review disposition, commonly bill_created, completed_outside_mason, duplicate, not_an_invoice, or archived."}},{"name":"pmApproved","in":"query","required":false,"description":"Exact match on pmApproved. Whether the invoice is marked approved.","schema":{"type":"boolean","description":"Exact match on pmApproved. Whether the invoice is marked approved."}},{"name":"pmRejected","in":"query","required":false,"description":"Exact match on pmRejected. Whether the invoice is marked rejected.","schema":{"type":"boolean","description":"Exact match on pmRejected. Whether the invoice is marked rejected."}},{"name":"needsReview","in":"query","required":false,"description":"Exact match on needsReview. Whether the recorded validation result requires review.","schema":{"type":"boolean","description":"Exact match on needsReview. Whether the recorded validation result requires review."}},{"name":"masonWorkOrderId","in":"query","required":false,"description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked."}},{"name":"workOrderNumber","in":"query","required":false,"description":"Case-insensitive literal substring match on workOrderNumber. Human-readable work-order number associated with the invoice. Percent and underscore characters are treated literally, not as wildcards.","schema":{"type":"string","description":"Case-insensitive literal substring match on workOrderNumber. Human-readable work-order number associated with the invoice. Percent and underscore characters are treated literally, not as wildcards."}},{"name":"invoiceNumber","in":"query","required":false,"description":"Case-insensitive literal substring match on invoiceNumber. Invoice number printed on the document. Percent and underscore characters are treated literally, not as wildcards.","schema":{"type":"string","description":"Case-insensitive literal substring match on invoiceNumber. Invoice number printed on the document. Percent and underscore characters are treated literally, not as wildcards."}},{"name":"emailSender","in":"query","required":false,"description":"Case-insensitive literal substring match on emailSender. Source email sender. Percent and underscore characters are treated literally, not as wildcards.","schema":{"type":"string","description":"Case-insensitive literal substring match on emailSender. Source email sender. Percent and underscore characters are treated literally, not as wildcards."}},{"name":"emailSubject","in":"query","required":false,"description":"Case-insensitive literal substring match on emailSubject. Source email subject. Percent and underscore characters are treated literally, not as wildcards.","schema":{"type":"string","description":"Case-insensitive literal substring match on emailSubject. Source email subject. Percent and underscore characters are treated literally, not as wildcards."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"updatedAfter","in":"query","required":false,"description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"updatedBefore","in":"query","required":false,"description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"invoiceDateAfter","in":"query","required":false,"description":"Inclusive lower bound on invoiceDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on invoiceDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"invoiceDateBefore","in":"query","required":false,"description":"Inclusive upper bound on invoiceDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on invoiceDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"dueDateAfter","in":"query","required":false,"description":"Inclusive lower bound on dueDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on dueDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"dueDateBefore","in":"query","required":false,"description":"Inclusive upper bound on dueDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on dueDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"pmsUploadedAfter","in":"query","required":false,"description":"Inclusive lower bound on pmsUploadedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on pmsUploadedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"pmsUploadedBefore","in":"query","required":false,"description":"Inclusive upper bound on pmsUploadedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on pmsUploadedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}}],"responses":{"200":{"description":"One page of invoices visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching invoices records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/Invoice"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"99999999-9999-4999-8999-999999999999","invoiceNumber":"INV-2041","invoiceDate":"2026-09-24T00:00:00.000Z","dueDate":"2026-10-24T00:00:00.000Z","totalAmount":24500,"currency":"USD","subtotal":22700,"tax":1800,"vendorInfo":{"name":"Example Plumbing Co.","email":"billing@plumbing.example.com","phone":"+15555550188"},"billToInfo":{"name":"Example Property Management"},"items":[{"description":"Replace kitchen faucet cartridge","quantity":1,"unitPrice":147,"totalPrice":147},{"description":"Labor","quantity":1,"unitPrice":80,"totalPrice":80}],"workOrderNumber":"1042-1","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","confidence":"high","isInvoice":true,"additionalNotes":null,"isRecurring":false,"recurringDescription":null,"matchedVendor":{"vendorId":"778","vendorName":"Example Plumbing Co.","confidence":"high"},"matchedProperty":{"propertyId":"3301","fullAddress":"123 Example St, Springfield, IL 62701","confidence":"high"},"matchedWorkOrder":{"workOrderId":"10042","workOrderNumber":"1042-1","confidence":"high"},"emailMessageId":"<invoice-2041@mail.example.com>","emailSender":"billing@plumbing.example.com","emailSubject":"Invoice INV-2041 for 123 Example St","filename":"INV-2041.pdf","pdfBlobUrl":"https://files.example.com/invoices/INV-2041.pdf","attachments":[{"filename":"INV-2041.pdf","mimeType":"application/pdf","size":48213,"blobUrl":"https://files.example.com/invoices/INV-2041.pdf"}],"status":"processed","reviewed":false,"reviewReason":null,"pmApproved":false,"pmApprovedAt":null,"pmApprovedBy":null,"pmRejected":false,"pmRejectedAt":null,"pmRejectionReason":null,"pmsUploadedAt":null,"pmsBillUrl":null,"workDoneDescription":"Replaced the kitchen faucet cartridge.","selectedGlAccountId":"6400","selectedTerms":"Net 30","selectedMarkupPercentage":10,"selectedMarkupAccountId":"4800","selectedDiscountPercentage":null,"shareInvoiceWithOwner":false,"suggestedBillSplits":null,"tenantChargeSignal":null,"needsReview":false,"agreementValidation":{"isValid":true,"confidence":"high"},"createdAt":"2026-09-24T17:00:00.000Z","updatedAt":"2026-09-24T17:05:00.000Z"}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/invoices/{id}":{"get":{"tags":["invoices"],"operationId":"getInvoice","summary":"Get one invoices record","description":"Stored invoices, matching results, and review/billing state. Top-level monetary amounts are integer cents. Nested document data is returned as stored, except that line-item quantities and amounts, matched-record identifiers, and party addresses are returned in their documented types; a stored value that cannot be read as that type is null.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404. The ETag response header identifies this version of the invoice; send it as If-Match when deciding it.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Invoice"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"99999999-9999-4999-8999-999999999999","invoiceNumber":"INV-2041","invoiceDate":"2026-09-24T00:00:00.000Z","dueDate":"2026-10-24T00:00:00.000Z","totalAmount":24500,"currency":"USD","subtotal":22700,"tax":1800,"vendorInfo":{"name":"Example Plumbing Co.","email":"billing@plumbing.example.com","phone":"+15555550188"},"billToInfo":{"name":"Example Property Management"},"items":[{"description":"Replace kitchen faucet cartridge","quantity":1,"unitPrice":147,"totalPrice":147},{"description":"Labor","quantity":1,"unitPrice":80,"totalPrice":80}],"workOrderNumber":"1042-1","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","confidence":"high","isInvoice":true,"additionalNotes":null,"isRecurring":false,"recurringDescription":null,"matchedVendor":{"vendorId":"778","vendorName":"Example Plumbing Co.","confidence":"high"},"matchedProperty":{"propertyId":"3301","fullAddress":"123 Example St, Springfield, IL 62701","confidence":"high"},"matchedWorkOrder":{"workOrderId":"10042","workOrderNumber":"1042-1","confidence":"high"},"emailMessageId":"<invoice-2041@mail.example.com>","emailSender":"billing@plumbing.example.com","emailSubject":"Invoice INV-2041 for 123 Example St","filename":"INV-2041.pdf","pdfBlobUrl":"https://files.example.com/invoices/INV-2041.pdf","attachments":[{"filename":"INV-2041.pdf","mimeType":"application/pdf","size":48213,"blobUrl":"https://files.example.com/invoices/INV-2041.pdf"}],"status":"processed","reviewed":false,"reviewReason":null,"pmApproved":false,"pmApprovedAt":null,"pmApprovedBy":null,"pmRejected":false,"pmRejectedAt":null,"pmRejectionReason":null,"pmsUploadedAt":null,"pmsBillUrl":null,"workDoneDescription":"Replaced the kitchen faucet cartridge.","selectedGlAccountId":"6400","selectedTerms":"Net 30","selectedMarkupPercentage":10,"selectedMarkupAccountId":"4800","selectedDiscountPercentage":null,"shareInvoiceWithOwner":false,"suggestedBillSplits":null,"tenantChargeSignal":null,"needsReview":false,"agreementValidation":{"isValid":true,"confidence":"high"},"createdAt":"2026-09-24T17:00:00.000Z","updatedAt":"2026-09-24T17:05:00.000Z"}}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the invoice, derived from its updatedAt. Send it as If-Match on PATCH /invoices/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-24T17:05:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"patch":{"tags":["invoices"],"operationId":"updateInvoice","summary":"Approve an invoice to pay, or reject it","description":"Approves the invoice to pay or rejects it as a property manager does in Mason, selected by decision in the body. The invoice's status field is its processing state and does not change; pmApproved and pmRejected record the decision. Recorded in the work-order activity log as this API key. Requires a read & write API key.\n\nWith decision approved, pmApproved becomes true and pmApprovedBy records this API key's name. Approval does not create a bill or payment in your property management system; bills are created separately in Mason. The invoice needs an amount greater than zero and an invoice number, or confirmMissingInvoiceNumber: true. When the invoice's property is inactive in your property management system the request returns 409 unless confirmInactiveProperty is true. No message is sent.\n\nWith decision rejected, pmRejected becomes true and any approval is withdrawn. When the invoice is linked to a RentVine invoice, Mason declines it in RentVine first and rejects it in Mason only after RentVine confirms. An invoice already processed (reviewed, or uploaded to your property management system) cannot be rejected. No message is sent to the vendor.\n\nRepeating a decision is safe and needs no Idempotency-Key: when pmApproved is already true and you send approved, or pmRejected is already true and you send rejected, the request returns 200 with the current invoice and nothing runs. The check is not a lock: two identical requests arriving at the same moment can both run the operation, as in the Mason app. Sending the opposite decision reverses the earlier one, as in Mason.\n\nOptimistic concurrency: this endpoint and GET /invoices/{id} return an ETag derived from the invoice's updatedAt. Sending it as If-Match is strongly recommended: when the invoice changed since that read, the request returns 412 before anything runs. updatedAt advances on any change to the invoice record, including changes made by Mason's own processing and property management system sync, so a 412 can occur without another API client. The check is not a lock: a change made while this request is being applied is not detected. A retry after a lost response that re-sends the If-Match value read before the first attempt returns 412, because the first attempt changed the record; re-read the record and compare its state before retrying.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the invoice id field.","schema":{"type":"string","format":"uuid"}},{"name":"If-Match","in":"header","required":false,"description":"Strongly recommended. The ETag from your latest read of this invoice; a comma-separated list is accepted. When none matches the current ETag, the request returns 412 and nothing runs. * matches any existing invoice. When omitted, the decision applies regardless of intervening updates.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInvoiceRequest"},"examples":{"approve":{"summary":"Approve to pay","value":{"decision":"approved"}},"approveMissingNumber":{"summary":"Approve an invoice with no number","value":{"decision":"approved","confirmMissingInvoiceNumber":true}},"approveInactiveProperty":{"summary":"Approve although the invoice's property is inactive","value":{"decision":"approved","confirmInactiveProperty":true}},"reject":{"summary":"Reject with a reason","value":{"decision":"rejected","reason":"Labor was billed twice."}}}}}},"responses":{"200":{"description":"The invoice after the decision, or unchanged when it was already in the requested state.","headers":{"ETag":{"description":"Strong validator for this version of the invoice, derived from its updatedAt. Send it as If-Match on PATCH /invoices/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-25T13:00:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Invoice"}}},"examples":{"approved":{"summary":"Approved to pay","value":{"data":{"id":"99999999-9999-4999-8999-999999999999","invoiceNumber":"INV-2041","invoiceDate":"2026-09-24T00:00:00.000Z","dueDate":"2026-10-24T00:00:00.000Z","totalAmount":24500,"currency":"USD","subtotal":22700,"tax":1800,"vendorInfo":{"name":"Example Plumbing Co.","email":"billing@plumbing.example.com","phone":"+15555550188"},"billToInfo":{"name":"Example Property Management"},"items":[{"description":"Replace kitchen faucet cartridge","quantity":1,"unitPrice":147,"totalPrice":147},{"description":"Labor","quantity":1,"unitPrice":80,"totalPrice":80}],"workOrderNumber":"1042-1","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","confidence":"high","isInvoice":true,"additionalNotes":null,"isRecurring":false,"recurringDescription":null,"matchedVendor":{"vendorId":"778","vendorName":"Example Plumbing Co.","confidence":"high"},"matchedProperty":{"propertyId":"3301","fullAddress":"123 Example St, Springfield, IL 62701","confidence":"high"},"matchedWorkOrder":{"workOrderId":"10042","workOrderNumber":"1042-1","confidence":"high"},"emailMessageId":"<invoice-2041@mail.example.com>","emailSender":"billing@plumbing.example.com","emailSubject":"Invoice INV-2041 for 123 Example St","filename":"INV-2041.pdf","pdfBlobUrl":"https://files.example.com/invoices/INV-2041.pdf","attachments":[{"filename":"INV-2041.pdf","mimeType":"application/pdf","size":48213,"blobUrl":"https://files.example.com/invoices/INV-2041.pdf"}],"status":"processed","reviewed":false,"reviewReason":null,"pmApproved":true,"pmApprovedAt":"2026-09-25T13:00:00.000Z","pmApprovedBy":"External API key \"Example integration\"","pmRejected":false,"pmRejectedAt":null,"pmRejectionReason":null,"pmsUploadedAt":null,"pmsBillUrl":null,"workDoneDescription":"Replaced the kitchen faucet cartridge.","selectedGlAccountId":"6400","selectedTerms":"Net 30","selectedMarkupPercentage":10,"selectedMarkupAccountId":"4800","selectedDiscountPercentage":null,"shareInvoiceWithOwner":false,"suggestedBillSplits":null,"tenantChargeSignal":null,"needsReview":false,"agreementValidation":{"isValid":true,"confidence":"high"},"createdAt":"2026-09-24T17:00:00.000Z","updatedAt":"2026-09-25T13:00:00.000Z"}}},"rejected":{"summary":"Rejected","value":{"data":{"id":"99999999-9999-4999-8999-999999999999","invoiceNumber":"INV-2041","invoiceDate":"2026-09-24T00:00:00.000Z","dueDate":"2026-10-24T00:00:00.000Z","totalAmount":24500,"currency":"USD","subtotal":22700,"tax":1800,"vendorInfo":{"name":"Example Plumbing Co.","email":"billing@plumbing.example.com","phone":"+15555550188"},"billToInfo":{"name":"Example Property Management"},"items":[{"description":"Replace kitchen faucet cartridge","quantity":1,"unitPrice":147,"totalPrice":147},{"description":"Labor","quantity":1,"unitPrice":80,"totalPrice":80}],"workOrderNumber":"1042-1","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","confidence":"high","isInvoice":true,"additionalNotes":null,"isRecurring":false,"recurringDescription":null,"matchedVendor":{"vendorId":"778","vendorName":"Example Plumbing Co.","confidence":"high"},"matchedProperty":{"propertyId":"3301","fullAddress":"123 Example St, Springfield, IL 62701","confidence":"high"},"matchedWorkOrder":{"workOrderId":"10042","workOrderNumber":"1042-1","confidence":"high"},"emailMessageId":"<invoice-2041@mail.example.com>","emailSender":"billing@plumbing.example.com","emailSubject":"Invoice INV-2041 for 123 Example St","filename":"INV-2041.pdf","pdfBlobUrl":"https://files.example.com/invoices/INV-2041.pdf","attachments":[{"filename":"INV-2041.pdf","mimeType":"application/pdf","size":48213,"blobUrl":"https://files.example.com/invoices/INV-2041.pdf"}],"status":"processed","reviewed":false,"reviewReason":null,"pmApproved":false,"pmApprovedAt":null,"pmApprovedBy":null,"pmRejected":true,"pmRejectedAt":"2026-09-25T13:00:00.000Z","pmRejectionReason":"Labor was billed twice.","pmsUploadedAt":null,"pmsBillUrl":null,"workDoneDescription":"Replaced the kitchen faucet cartridge.","selectedGlAccountId":"6400","selectedTerms":"Net 30","selectedMarkupPercentage":10,"selectedMarkupAccountId":"4800","selectedDiscountPercentage":null,"shareInvoiceWithOwner":false,"suggestedBillSplits":null,"tenantChargeSignal":null,"needsReview":false,"agreementValidation":{"isValid":true,"confidence":"high"},"createdAt":"2026-09-24T17:00:00.000Z","updatedAt":"2026-09-25T13:00:00.000Z"}}}}}}},"400":{"description":"Invalid JSON or fields, a missing or unknown decision, or a field that belongs to the other decision (confirmMissingInvoiceNumber and confirmInactiveProperty are accepted only with approved; reason only with rejected). On approval, also an invoice amount that is not greater than zero, or a missing invoice number without confirmMissingInvoiceNumber: correct the invoice in Mason or send confirmMissingInvoiceNumber: true, and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"wrongDecisionField":{"summary":"An approval field sent with rejected","value":{"error":"Invalid request body. Unrecognized key: \"confirmInactiveProperty\"","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"missingNumber":{"summary":"Invoice number missing","value":{"error":"Enter an invoice number or confirm that this invoice has no number. Correct the invoice in Mason, or send confirmMissingInvoiceNumber: true to approve an invoice that has no number, and retry.","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No invoice exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"409":{"description":"On approval, the invoice's property is inactive in your property management system and confirmInactiveProperty was not true; send confirmInactiveProperty: true and retry. On rejection, the invoice was already processed, changed during the request, or its RentVine link cannot be declined.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"inactiveProperty":{"summary":"Property inactive in the property management system","value":{"error":"This invoice's property (123 Example St) is inactive in your property management system. Confirm the property is correct, then send confirmInactiveProperty: true and retry.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"alreadyProcessed":{"summary":"Rejection of an invoice already processed","value":{"error":"This invoice has already been processed and cannot be rejected","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"412":{"description":"If-Match did not match the current ETag. Nothing ran. The ETag header carries the current version; read the invoice again before retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"staleEtag":{"summary":"The invoice changed since it was read","value":{"error":"The invoice changed since the If-Match version was read. Fetch it again and retry with the new ETag.","code":"precondition_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the invoice, derived from its updatedAt. Send it as If-Match on PATCH /invoices/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-24T17:05:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"502":{"description":"On rejection, RentVine did not confirm the decline, so Mason did not reject the invoice; or RentVine declined it but Mason could not record the rejection. The error says which.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"declineNotConfirmed":{"summary":"RentVine did not confirm the decline","value":{"error":"The PMS did not confirm the invoice decline. Mason has not rejected it.","code":"pms_write_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/contacts":{"get":{"tags":["contacts"],"operationId":"listContact","summary":"List contacts","description":"People and businesses in your property management account. Hydrate contact references with a detail request or the id/ids filters, even when the contact predates your incremental sync window. Tenant (resident), owner, and vendor contacts are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. Technician, property-manager, emergency, and unidentified contacts are maintained in Mason. POST /contacts creates vendor contacts only: in RentVine or AppFolio first when your account is connected to one, otherwise in Mason alone. PATCH /contacts/{id} changes only the Mason-maintained fields preferredContactMethod, language, stopAllComms, and notes, which Mason does not write to your property management system; every other field is read-only here, and fields your property management system provides change only there.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"id","in":"query","required":false,"description":"Filter by one or more comma-separated Mason contact UUIDs. id and ids are aliases; when both are supplied their IDs are combined. Invalid UUID entries are ignored, and a set with no valid IDs matches nothing. Results still use normal pagination.","schema":{"type":"string","description":"Filter by one or more comma-separated Mason contact UUIDs. id and ids are aliases; when both are supplied their IDs are combined. Invalid UUID entries are ignored, and a set with no valid IDs matches nothing. Results still use normal pagination."}},{"name":"ids","in":"query","required":false,"description":"Filter by one or more comma-separated Mason contact UUIDs. id and ids are aliases; when both are supplied their IDs are combined. Invalid UUID entries are ignored, and a set with no valid IDs matches nothing. Results still use normal pagination.","schema":{"type":"string","description":"Filter by one or more comma-separated Mason contact UUIDs. id and ids are aliases; when both are supplied their IDs are combined. Invalid UUID entries are ignored, and a set with no valid IDs matches nothing. Results still use normal pagination."}},{"name":"contactType","in":"query","required":false,"description":"Exact match on contactType. Contact category, such as tenant, vendor, owner, tech, or property_manager.","schema":{"type":"string","description":"Exact match on contactType. Contact category, such as tenant, vendor, owner, tech, or property_manager."}},{"name":"isActive","in":"query","required":false,"description":"Exact match on isActive. Whether the contact is marked active.","schema":{"type":"boolean","description":"Exact match on isActive. Whether the contact is marked active."}},{"name":"search","in":"query","required":false,"description":"Case-insensitive literal substring match on name. Contact display name. Percent and underscore characters are treated literally, not as wildcards.","schema":{"type":"string","description":"Case-insensitive literal substring match on name. Contact display name. Percent and underscore characters are treated literally, not as wildcards."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"updatedAfter","in":"query","required":false,"description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"updatedBefore","in":"query","required":false,"description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}}],"responses":{"200":{"description":"One page of contacts visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching contacts records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/Contact"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"44444444-4444-4444-8444-444444444444","name":"Jordan Example","phoneNumber":"+15555550123","email":"jordan@example.com","contactType":"tenant","isActive":true,"preferredContactMethod":"text","language":"en","pmsUniqueId":"tenant-5521","createdAt":"2026-01-10T12:00:00.000Z","updatedAt":"2026-09-21T15:10:00.000Z","sentiment":{"value":"positive","score":4,"confidence":"medium","assessedAt":"2026-09-21T16:00:00.000Z","sourceWorkOrderId":"11111111-1111-4111-8111-111111111111"},"stopAllComms":false,"notes":"Works nights; text before 10 AM only for emergencies."}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"post":{"tags":["contacts"],"operationId":"createContact","summary":"Create a vendor contact","description":"Creates a vendor through the same path Mason uses when a property manager asks it to add one. When your account is connected to RentVine or AppFolio, Mason first creates the vendor there, so your property management system gets a new vendor record, then saves it in Mason as a vendor contact linked to that record. Accounts with no connected system get a vendor in Mason only. Accounts on PropertyWare, Buildium, or Property Meld cannot create vendors here and receive 409; create the vendor in your property management system instead, and Mason picks it up on its next sync. Only vendors can be created: send contactType vendor. Before creating anything, Mason looks for the vendor among your contacts in Mason and, when connected, in its synced copy of your RentVine or AppFolio vendors; a vendor added there since the last sync is not seen, so it can be created a second time. A vendor with the same name, ignoring capitalization, and a matching phone number or email is reused instead of duplicated: the request returns 200 with created false. A partial match, such as the same phone number under a different name, returns 409 and creates nothing. Otherwise the request returns 201 with created true. Mason does not message, dispatch, or invite the vendor. Test accounts can create vendors only when they have no connected property management system, where the vendor is created in the test account in Mason alone; a test account connected to RentVine or AppFolio receives 409, because the write would reach the live property management system. The ETag response header identifies this version of the contact; send it as If-Match on PATCH /contacts/{id}. Requires a read & write API key. Send a unique Idempotency-Key per vendor; a retry with the same key and body returns the original response instead of creating the vendor again.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Client-chosen key, unique per vendor you intend to create (for example a UUID or your own vendor record ID). 1-255 printable ASCII characters. Reusing it with a different body returns 422.","schema":{"type":"string","minLength":1,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactRequest"},"examples":{"vendorWithPhone":{"summary":"A vendor with a phone number","value":{"contactType":"vendor","name":"Example Plumbing Co.","phoneNumber":"(555) 555-0188"}},"vendorWithEmail":{"summary":"A vendor with an email and a contact person","value":{"contactType":"vendor","name":"Example Electric LLC","email":"dispatch@electric.example.com","firstName":"Riley","lastName":"Example"}}}}}},"responses":{"200":{"description":"The name and contact details matched an existing vendor, so nothing new was created in your property management system. created is false and data is that vendor's Mason contact, linked and updated as the created field describes. A replayed response carries the header Idempotent-Replayed: true.","headers":{"ETag":{"description":"Strong validator for this version of the contact, derived from its updatedAt. Send it as If-Match on PATCH /contacts/{id}. Treat it as opaque. Absent on a replayed response; read the contact to get it.","schema":{"type":"string"},"example":"\"2026-09-23T18:20:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","description":"Contact create response.","required":["data","pmsSyncError","created"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Contact"},"pmsSyncError":{"type":["string","null"],"description":"Always null for a vendor: when the write to your property management system fails, or Mason cannot save the vendor that system just created, the request returns 502 instead."},"created":{"type":"boolean","description":"true (status 201) when this request created a new vendor: in RentVine or AppFolio when your account is connected to one, where data is the Mason contact saved for it (a new contact, or an existing Mason vendor contact with the same name and details that was not yet linked to your property management system); otherwise in Mason, as a new contact. false (status 200) when a vendor with the same name, ignoring capitalization, and a matching phone number or email already existed, so nothing new was created in your property management system, and data is that vendor's Mason contact: linked to the matching RentVine or AppFolio vendor if it was not linked already, creating the Mason contact when there was none, or, with no connected system, reused the matching Mason vendor. Either way, Mason marked the contact active, set its name to the name you sent, and may have filled in a phone number or email the contact did not have. An existing phone number or email is never replaced."}}},"examples":{"matchedExisting":{"summary":"Matched an existing vendor, which Mason linked and reactivated","value":{"data":{"id":"55555555-5555-4555-8555-555555555555","name":"Example Plumbing Co.","phoneNumber":"+15555550188","email":null,"contactType":"vendor","isActive":true,"preferredContactMethod":"phone","language":"en","pmsUniqueId":"vendor_778","createdAt":"2026-03-02T15:00:00.000Z","updatedAt":"2026-09-23T18:20:00.000Z","sentiment":null,"stopAllComms":false,"notes":null},"pmsSyncError":null,"created":false}}}}}},"201":{"description":"A new vendor was created: in RentVine or AppFolio and saved in Mason when your account is connected to one, otherwise in Mason. created is true and data is its Mason contact. A replayed response carries the header Idempotent-Replayed: true.","headers":{"ETag":{"description":"Strong validator for this version of the contact, derived from its updatedAt. Send it as If-Match on PATCH /contacts/{id}. Treat it as opaque. Absent on a replayed response; read the contact to get it.","schema":{"type":"string"},"example":"\"2026-09-23T18:20:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","description":"Contact create response.","required":["data","pmsSyncError","created"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Contact"},"pmsSyncError":{"type":["string","null"],"description":"Always null for a vendor: when the write to your property management system fails, or Mason cannot save the vendor that system just created, the request returns 502 instead."},"created":{"type":"boolean","description":"true (status 201) when this request created a new vendor: in RentVine or AppFolio when your account is connected to one, where data is the Mason contact saved for it (a new contact, or an existing Mason vendor contact with the same name and details that was not yet linked to your property management system); otherwise in Mason, as a new contact. false (status 200) when a vendor with the same name, ignoring capitalization, and a matching phone number or email already existed, so nothing new was created in your property management system, and data is that vendor's Mason contact: linked to the matching RentVine or AppFolio vendor if it was not linked already, creating the Mason contact when there was none, or, with no connected system, reused the matching Mason vendor. Either way, Mason marked the contact active, set its name to the name you sent, and may have filled in a phone number or email the contact did not have. An existing phone number or email is never replaced."}}},"examples":{"createdInPms":{"summary":"Created in RentVine and saved in Mason","value":{"data":{"id":"55555555-5555-4555-8555-555555555555","name":"Example Plumbing Co.","phoneNumber":"+15555550188","email":null,"contactType":"vendor","isActive":true,"preferredContactMethod":"phone","language":"en","pmsUniqueId":"vendor_778","createdAt":"2026-09-23T18:20:00.000Z","updatedAt":"2026-09-23T18:20:00.000Z","sentiment":null,"stopAllComms":false,"notes":null},"pmsSyncError":null,"created":true}},"createdInMason":{"summary":"Created in Mason, with no connected system","value":{"data":{"id":"55555555-5555-4555-8555-555555555555","name":"Example Plumbing Co.","phoneNumber":"+15555550188","email":null,"contactType":"vendor","isActive":true,"preferredContactMethod":"phone","language":"en","pmsUniqueId":null,"createdAt":"2026-09-23T18:20:00.000Z","updatedAt":"2026-09-23T18:20:00.000Z","sentiment":null,"stopAllComms":false,"notes":null},"pmsSyncError":null,"created":true}}}}}},"400":{"description":"Invalid JSON; an unknown field; a contactType other than vendor; a missing or blank name; a body with neither phoneNumber nor email; an invalid email address; a phone number that is not a valid US number; or a missing Idempotency-Key. The phone number is checked after the Idempotency-Key is reserved, so that 400 is replayed for the same key; retry with a new key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notAVendor":{"summary":"A contact type other than vendor","value":{"error":"Invalid request body. contactType: Only vendor contacts can be created through the API today: send contactType \"vendor\". Tenants, owners, and other contact types come from your property management system or are added in Mason.","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"noChannel":{"summary":"Neither phone nor email","value":{"error":"Invalid request body. Provide at least one of: phoneNumber, email","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"invalidPhone":{"summary":"Not a valid US phone number","value":{"error":"Enter a valid US vendor phone number.","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"keyRequired":{"summary":"Missing Idempotency-Key","value":{"error":"Idempotency-Key header is required: 1-255 printable ASCII characters, unique per write.","code":"idempotency_key_required","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"The API key's property management account was not found. Nothing was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"409":{"description":"The details conflict with an existing vendor, and Mason created or linked nothing: the phone number or email belongs to a vendor with a different name, in Mason or in your property management system; your property management system already has a vendor with this name but different contact details, or several vendors matching these details; the Mason vendor with this phone number or email has a different email or phone number; the phone number and email belong to different vendors; or the matching Mason vendor is linked to a different property management record. The message names the conflicting vendor where it can; resolve the conflict in Mason or your property management system before retrying. Also returned when the account cannot create vendors here: its property management system is not RentVine or AppFolio, it is a test account connected to one, or its RentVine or AppFolio connection is missing or inactive. This response is stored under the Idempotency-Key, so retry with a new key. A request with this Idempotency-Key that is still in progress or did not finish also returns 409.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"channelTaken":{"summary":"Phone number belongs to a differently named vendor","value":{"error":"The supplied phone or email already belongs to vendor \"Example Plumbing Services\" in Mason. Use that contact or provide a different channel before creating another vendor.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"nameTaken":{"summary":"Same name with different details in the property management system","value":{"error":"RentVine already has a vendor named \"Example Plumbing Co.\" with different contact details. Review that vendor before creating another one.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"unsupportedPms":{"summary":"Account on a property management system without vendor creation","value":{"error":"Vendor creation through the API is available for accounts on RentVine, AppFolio, or no connected property management system. Create the vendor in your property management system; Mason picks it up on its next sync.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"testAccount":{"summary":"Test account connected to a live property management system","value":{"error":"Vendor creation is disabled in test property-manager accounts because it writes to the connected live PMS.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"inProgress":{"summary":"Same Idempotency-Key still in progress","value":{"error":"A request with this Idempotency-Key is still in progress.","code":"idempotency_in_progress","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"unfinished":{"summary":"Same Idempotency-Key did not finish","value":{"error":"A previous request with this Idempotency-Key did not finish. Check whether it took effect before retrying with a new key.","code":"idempotency_request_unfinished","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"422":{"description":"This Idempotency-Key was already used with a different request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"keyReused":{"summary":"Idempotency-Key reused with a different body","value":{"error":"This Idempotency-Key was already used with a different request.","code":"idempotency_key_reused","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"Either the request failed and may have partially taken effect, so the vendor may exist in your property management system or in Mason, or the vendor was saved in Mason but could not be read back to return it, in which case the message names its id: fetch it with GET /contacts/{id} instead of resending. The same Idempotency-Key replays this failure; check before retrying with a new key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"writeFailed":{"summary":"Write may have partially taken effect","value":{"error":"The request failed and may have partially taken effect, in Mason or in your property management system. Check both before retrying with a new Idempotency-Key.","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"502":{"description":"The write to your property management system failed: RentVine or AppFolio rejected the vendor or did not confirm whether it was created, or created it but Mason could not save it. The message says which. When the vendor may exist in your property management system, check there before creating it again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"pmsRejected":{"summary":"RentVine rejected the vendor","value":{"error":"RentVine rejected vendor creation (422): The email address is not valid.","code":"pms_write_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"pmsUnconfirmed":{"summary":"RentVine did not confirm the create","value":{"error":"RentVine did not confirm whether the vendor was created. Do not retry creation; check RentVine or run the vendor sync first.","code":"pms_write_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/contacts/{id}":{"get":{"tags":["contacts"],"operationId":"getContact","summary":"Get one contacts record","description":"People and businesses in your property management account. Hydrate contact references with a detail request or the id/ids filters, even when the contact predates your incremental sync window. Tenant (resident), owner, and vendor contacts are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. Technician, property-manager, emergency, and unidentified contacts are maintained in Mason. POST /contacts creates vendor contacts only: in RentVine or AppFolio first when your account is connected to one, otherwise in Mason alone. PATCH /contacts/{id} changes only the Mason-maintained fields preferredContactMethod, language, stopAllComms, and notes, which Mason does not write to your property management system; every other field is read-only here, and fields your property management system provides change only there.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404. The ETag response header identifies this version of the contact; send it as If-Match when changing it.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Contact"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"44444444-4444-4444-8444-444444444444","name":"Jordan Example","phoneNumber":"+15555550123","email":"jordan@example.com","contactType":"tenant","isActive":true,"preferredContactMethod":"text","language":"en","pmsUniqueId":"tenant-5521","createdAt":"2026-01-10T12:00:00.000Z","updatedAt":"2026-09-21T15:10:00.000Z","sentiment":{"value":"positive","score":4,"confidence":"medium","assessedAt":"2026-09-21T16:00:00.000Z","sourceWorkOrderId":"11111111-1111-4111-8111-111111111111"},"stopAllComms":false,"notes":"Works nights; text before 10 AM only for emergencies."}}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the contact, derived from its updatedAt. Send it as If-Match on PATCH /contacts/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-21T15:10:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"patch":{"tags":["contacts"],"operationId":"updateContact","summary":"Update a contact's Mason-maintained fields","description":"Changes only the Mason-maintained fields listed in the request schema, as a property manager would in Mason. Nothing is written to your property management system, and fields that come from it stay read-only here and change only there. Requires a read & write API key. Sending a value a field already has is safe and needs no Idempotency-Key; nothing else runs. Send any of preferredContactMethod, language, stopAllComms, and notes; omitted fields are left unchanged. stopAllComms: true takes effect starting with the next Mason-initiated message to this contact. notes replaces the stored notes in full; send null to clear them.\n\nOptimistic concurrency: this endpoint and GET /contacts/{id} return an ETag derived from the contact's updatedAt. Sending it as If-Match is strongly recommended: when the contact changed since that read, the request returns 412 before any field is applied. updatedAt advances when the contact's Mason-maintained fields change. The check is not a lock: a change made while this request is being applied is not detected.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the contact id field.","schema":{"type":"string","format":"uuid"}},{"name":"If-Match","in":"header","required":false,"description":"Strongly recommended. The ETag from your latest read of this contact; a comma-separated list is accepted. When none matches the current ETag, the request returns 412 and applies nothing. * matches any existing contact. When omitted, the changes apply regardless of intervening updates.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContactRequest"},"examples":{"setTextSpanish":{"summary":"Switch to text messages in Spanish","value":{"preferredContactMethod":"text","language":"es"}},"blockComms":{"summary":"Block Mason messages and note why","value":{"stopAllComms":true,"notes":"Asked to be contacted only through the property manager."}},"clearNotes":{"summary":"Clear the stored notes","value":{"notes":null}}}}}},"responses":{"200":{"description":"The contact after the change, or unchanged when every field already had the requested value.","headers":{"ETag":{"description":"Strong validator for this version of the contact, derived from its updatedAt. Send it as If-Match on PATCH /contacts/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-23T18:00:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Contact"}}},"examples":{"updated":{"summary":"Updated","value":{"data":{"id":"44444444-4444-4444-8444-444444444444","name":"Jordan Example","phoneNumber":"+15555550123","email":"jordan@example.com","contactType":"tenant","isActive":true,"preferredContactMethod":"text","language":"es","pmsUniqueId":"tenant-5521","createdAt":"2026-01-10T12:00:00.000Z","updatedAt":"2026-09-23T18:00:00.000Z","sentiment":{"value":"positive","score":4,"confidence":"medium","assessedAt":"2026-09-21T16:00:00.000Z","sourceWorkOrderId":"11111111-1111-4111-8111-111111111111"},"stopAllComms":false,"notes":"Works nights; text before 10 AM only for emergencies."}}}}}}},"400":{"description":"Invalid JSON or fields, an unrecognized field or one only your property management system can set, or a body with none of preferredContactMethod, language, stopAllComms, or notes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"noUpdatableField":{"summary":"No updatable field","value":{"error":"Invalid request body. Provide at least one of: preferredContactMethod, language, stopAllComms, notes","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No contact exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"412":{"description":"If-Match did not match the current ETag. No field was applied. The ETag header carries the current version; read the contact again before retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"staleEtag":{"summary":"The contact changed since it was read","value":{"error":"The contact changed since the If-Match version was read. Fetch it again and retry with the new ETag.","code":"precondition_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the contact, derived from its updatedAt. Send it as If-Match on PATCH /contacts/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-21T15:10:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/visits":{"get":{"tags":["visits"],"operationId":"listVisit","summary":"List visits","description":"Maintenance visit records. Assigned technicians describe assignment, not completed labor. Nested JSON is returned as stored; changes to related records do not necessarily update this record timestamp.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Exact match on status. Recorded disposition, commonly Complete, Still Working, Canceled, Estimate, or an empty string.","schema":{"type":"string","description":"Exact match on status. Recorded disposition, commonly Complete, Still Working, Canceled, Estimate, or an empty string."}},{"name":"priority","in":"query","required":false,"description":"Exact match on priority. Recorded visit priority, commonly urgent, normal, or low.","schema":{"type":"string","description":"Exact match on priority. Recorded visit priority, commonly urgent, normal, or low."}},{"name":"noteReviewed","in":"query","required":false,"description":"Exact match on noteReviewed. Whether the office has reviewed the recorded work notes; null means not recorded.","schema":{"type":"boolean","description":"Exact match on noteReviewed. Whether the office has reviewed the recorded work notes; null means not recorded."}},{"name":"assignedTech","in":"query","required":false,"description":"Match visits whose assignedTechs contains this exact Mason technician contact ID.","schema":{"type":"string","description":"Match visits whose assignedTechs contains this exact Mason technician contact ID."}},{"name":"initialRoutingTech","in":"query","required":false,"description":"Match visits whose legacy initialRouting contains this exact technician name.","schema":{"type":"string","description":"Match visits whose legacy initialRouting contains this exact technician name."}},{"name":"masonWorkOrderId","in":"query","required":false,"description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked."}},{"name":"logDateAfter","in":"query","required":false,"description":"Inclusive lower bound on logDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on logDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"logDateBefore","in":"query","required":false,"description":"Inclusive upper bound on logDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on logDate. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"updatedAfter","in":"query","required":false,"description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"updatedBefore","in":"query","required":false,"description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}}],"responses":{"200":{"description":"One page of visits visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching visits records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/Visit"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"77777777-7777-4777-8777-777777777777","logDate":"2026-09-25T00:00:00.000Z","controlNumber":"CN-1042","location":"123 Example St, Unit 2B, Springfield, IL 62701","problem":"Kitchen faucet is leaking under the sink.","instructions":"Replace the faucet cartridge and check the supply lines.","priority":"normal","status":"Still Working","noteReviewed":false,"initialRouting":[],"workNotes":null,"estimate":null,"activity":[{"event":"assigned","timestamp":"2026-09-22T14:00:00.000Z"}],"assignedTechs":["66666666-6666-4666-8666-666666666666"],"masonWorkOrderId":"11111111-1111-4111-8111-111111111111","createdAt":"2026-09-22T14:00:00.000Z","updatedAt":"2026-09-25T18:30:00.000Z","techHours":[{"id":"14141414-1414-4141-8141-141414141414","techContactId":"66666666-6666-4666-8666-666666666666","workedOn":"2026-09-25","hours":"1.50","createdAt":"2026-09-25T18:30:00.000Z","updatedAt":"2026-09-25T18:30:00.000Z"}],"techClockSessions":[]}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/visits/{id}":{"get":{"tags":["visits"],"operationId":"getVisit","summary":"Get one visits record","description":"Maintenance visit records. Assigned technicians describe assignment, not completed labor. Nested JSON is returned as stored; changes to related records do not necessarily update this record timestamp.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Visit"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"77777777-7777-4777-8777-777777777777","logDate":"2026-09-25T00:00:00.000Z","controlNumber":"CN-1042","location":"123 Example St, Unit 2B, Springfield, IL 62701","problem":"Kitchen faucet is leaking under the sink.","instructions":"Replace the faucet cartridge and check the supply lines.","priority":"normal","status":"Still Working","noteReviewed":false,"initialRouting":[],"workNotes":null,"estimate":null,"activity":[{"event":"assigned","timestamp":"2026-09-22T14:00:00.000Z"}],"assignedTechs":["66666666-6666-4666-8666-666666666666"],"masonWorkOrderId":"11111111-1111-4111-8111-111111111111","createdAt":"2026-09-22T14:00:00.000Z","updatedAt":"2026-09-25T18:30:00.000Z","techHours":[{"id":"14141414-1414-4141-8141-141414141414","techContactId":"66666666-6666-4666-8666-666666666666","workedOn":"2026-09-25","hours":"1.50","createdAt":"2026-09-25T18:30:00.000Z","updatedAt":"2026-09-25T18:30:00.000Z"}],"techClockSessions":[]}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/properties":{"get":{"tags":["properties"],"operationId":"listProperty","summary":"List properties","description":"Properties associated with your account, including stored address, ownership, and provider details. No geocoding or owner lookup runs as part of this read. Properties are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. This API does not create properties. PATCH /properties/{id} changes only the Mason-maintained fields access and pauseOwnerOutreach, which Mason does not write to your property management system; every other field is read-only here and changes only in your property management system.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"isActive","in":"query","required":false,"description":"Exact match on isActive. Whether the property is marked active.","schema":{"type":"boolean","description":"Exact match on isActive. Whether the property is marked active."}},{"name":"city","in":"query","required":false,"description":"Exact match on city. City.","schema":{"type":"string","description":"Exact match on city. City."}},{"name":"state","in":"query","required":false,"description":"Exact match on state. State or region.","schema":{"type":"string","description":"Exact match on state. State or region."}},{"name":"search","in":"query","required":false,"description":"Case-insensitive literal substring match on formattedAddress. Formatted property address. Percent and underscore characters are treated literally, not as wildcards.","schema":{"type":"string","description":"Case-insensitive literal substring match on formattedAddress. Formatted property address. Percent and underscore characters are treated literally, not as wildcards."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"updatedAfter","in":"query","required":false,"description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"updatedBefore","in":"query","required":false,"description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"market","in":"query","required":false,"description":"Exact match on the stored propertyDetails.market value.","schema":{"type":"string","description":"Exact match on the stored propertyDetails.market value."}},{"name":"propertyClass","in":"query","required":false,"description":"Match properties whose stored propertyClass array contains this exact classification.","schema":{"type":"string","description":"Match properties whose stored propertyClass array contains this exact classification."}}],"responses":{"200":{"description":"One page of properties visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching properties records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/Property"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"22222222-2222-4222-8222-222222222222","formattedAddress":"123 Example St, Springfield, IL 62701","address":"123 Example St","address2":null,"city":"Springfield","state":"IL","zip":"62701","isActive":true,"multiUnit":true,"ownerInfo":[{"name":"Example Holdings LLC","email":"owner@example.com","isPrimary":true}],"propertyDetails":{"market":"Springfield","yearBuilt":1998},"createdAt":"2026-01-05T12:00:00.000Z","updatedAt":"2026-09-20T03:15:00.000Z","propertyClass":["residential"],"access":{"gateCode":"#4821","lockboxCode":null,"alarmCode":null,"notes":"Gate keypad is on the left pillar of the driveway."},"pauseOwnerOutreach":false}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/properties/{id}":{"get":{"tags":["properties"],"operationId":"getProperty","summary":"Get one properties record","description":"Properties associated with your account, including stored address, ownership, and provider details. No geocoding or owner lookup runs as part of this read. Properties are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. This API does not create properties. PATCH /properties/{id} changes only the Mason-maintained fields access and pauseOwnerOutreach, which Mason does not write to your property management system; every other field is read-only here and changes only in your property management system.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404. The ETag response header identifies this version of the property; send it as If-Match when changing it.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Property"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"22222222-2222-4222-8222-222222222222","formattedAddress":"123 Example St, Springfield, IL 62701","address":"123 Example St","address2":null,"city":"Springfield","state":"IL","zip":"62701","isActive":true,"multiUnit":true,"ownerInfo":[{"name":"Example Holdings LLC","email":"owner@example.com","isPrimary":true}],"propertyDetails":{"market":"Springfield","yearBuilt":1998},"createdAt":"2026-01-05T12:00:00.000Z","updatedAt":"2026-09-20T03:15:00.000Z","propertyClass":["residential"],"access":{"gateCode":"#4821","lockboxCode":null,"alarmCode":null,"notes":"Gate keypad is on the left pillar of the driveway."},"pauseOwnerOutreach":false}}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the property, derived from its updatedAt. Send it as If-Match on PATCH /properties/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-20T03:15:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"patch":{"tags":["properties"],"operationId":"updateProperty","summary":"Update a property's Mason-maintained fields","description":"Changes only the Mason-maintained fields listed in the request schema, as a property manager would in Mason. Nothing is written to your property management system, and fields that come from it stay read-only here and change only there. Requires a read & write API key. Sending a value a field already has is safe and needs no Idempotency-Key; nothing else runs. Send access and/or pauseOwnerOutreach; omitted fields are left unchanged. access is merged key by key into the property's stored access details: an omitted key is left unchanged and null clears a key. Access details are not yet included in the dispatch messages Mason sends vendors and technicians; that is a separate change. pauseOwnerOutreach is the Pause owner outreach switch on the Mason property page and takes effect starting with the next owner message.\n\nOptimistic concurrency: this endpoint and GET /properties/{id} return an ETag derived from the property's updatedAt. Sending it as If-Match is strongly recommended: when the property changed since that read, the request returns 412 before any field is applied. updatedAt advances when the property's Mason-maintained fields change. The check is not a lock: a change made while this request is being applied is not detected.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the property id field.","schema":{"type":"string","format":"uuid"}},{"name":"If-Match","in":"header","required":false,"description":"Strongly recommended. The ETag from your latest read of this property; a comma-separated list is accepted. When none matches the current ETag, the request returns 412 and applies nothing. * matches any existing property. When omitted, the changes apply regardless of intervening updates.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePropertyRequest"},"examples":{"pauseOutreach":{"summary":"Pause owner outreach","value":{"pauseOwnerOutreach":true}},"setAccessNotes":{"summary":"Set access notes","value":{"access":{"notes":"Gate keypad is on the left pillar of the driveway."}}}}}}},"responses":{"200":{"description":"The property after the change, or unchanged when every field already had the requested value.","headers":{"ETag":{"description":"Strong validator for this version of the property, derived from its updatedAt. Send it as If-Match on PATCH /properties/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-23T18:10:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Property"}}},"examples":{"updated":{"summary":"Updated","value":{"data":{"id":"22222222-2222-4222-8222-222222222222","formattedAddress":"123 Example St, Springfield, IL 62701","address":"123 Example St","address2":null,"city":"Springfield","state":"IL","zip":"62701","isActive":true,"multiUnit":true,"ownerInfo":[{"name":"Example Holdings LLC","email":"owner@example.com","isPrimary":true}],"propertyDetails":{"market":"Springfield","yearBuilt":1998},"createdAt":"2026-01-05T12:00:00.000Z","updatedAt":"2026-09-23T18:10:00.000Z","propertyClass":["residential"],"access":{"gateCode":"#4821","lockboxCode":null,"alarmCode":null,"notes":"Gate keypad is on the left pillar of the driveway."},"pauseOwnerOutreach":true}}}}}}},"400":{"description":"Invalid JSON or fields, an unrecognized field or one only your property management system can set, a body with neither access nor pauseOwnerOutreach, or an access object with none of gateCode, lockboxCode, alarmCode, or notes, or with a code over 64 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"noUpdatableField":{"summary":"No updatable field","value":{"error":"Invalid request body. Provide at least one of: access, pauseOwnerOutreach","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No property exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"412":{"description":"If-Match did not match the current ETag. No field was applied. The ETag header carries the current version; read the property again before retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"staleEtag":{"summary":"The property changed since it was read","value":{"error":"The property changed since the If-Match version was read. Fetch it again and retry with the new ETag.","code":"precondition_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the property, derived from its updatedAt. Send it as If-Match on PATCH /properties/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-20T03:15:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/scheduling-blocks":{"get":{"tags":["scheduling-blocks"],"operationId":"listSchedulingBlock","summary":"List scheduling-blocks","description":"Stored availability and appointment blocks. blockType=confirmed identifies a confirmed work window. A confirmed block and tenantConfirmationStatus are distinct facts. Range endpoints can be null for unbounded windows.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"masonWorkOrderId","in":"query","required":false,"description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked."}},{"name":"visitId","in":"query","required":false,"description":"Exact match on visitId. Linked Mason visit ID; resolve using GET /visits/{id}.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on visitId. Linked Mason visit ID; resolve using GET /visits/{id}."}},{"name":"contactId","in":"query","required":false,"description":"Exact match on contactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on contactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked."}},{"name":"blockType","in":"query","required":false,"description":"Exact match on blockType. Stored scheduling category, such as tenant_available, vendor_available, tentative, confirmed, tech_scheduling_proposal, blocked, superseded, on_call_assignment, on_call_override, or on_call_cancellation.","schema":{"type":"string","description":"Exact match on blockType. Stored scheduling category, such as tenant_available, vendor_available, tentative, confirmed, tech_scheduling_proposal, blocked, superseded, on_call_assignment, on_call_override, or on_call_cancellation."}},{"name":"source","in":"query","required":false,"description":"Exact match on source. Stored scheduling source, such as tenant_portal, vendor_portal, pm_manual, or ai_suggested.","schema":{"type":"string","description":"Exact match on source. Stored scheduling source, such as tenant_portal, vendor_portal, pm_manual, or ai_suggested."}},{"name":"tenantConfirmationStatus","in":"query","required":false,"description":"Exact match on tenantConfirmationStatus. Stored tenant confirmation status, commonly pending or confirmed; null means legacy or unknown.","schema":{"type":"string","description":"Exact match on tenantConfirmationStatus. Stored tenant confirmation status, commonly pending or confirmed; null means legacy or unknown."}},{"name":"linkKey","in":"query","required":false,"description":"Exact match on linkKey. Identifier grouping blocks from one scheduling submission.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on linkKey. Identifier grouping blocks from one scheduling submission."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"startAfter","in":"query","required":false,"description":"Inclusive lower bound on start. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on start. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"startBefore","in":"query","required":false,"description":"Inclusive upper bound on start. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on start. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"endAfter","in":"query","required":false,"description":"Inclusive lower bound on end. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on end. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"endBefore","in":"query","required":false,"description":"Inclusive upper bound on end. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on end. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}}],"responses":{"200":{"description":"One page of scheduling-blocks visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching scheduling-blocks records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/SchedulingBlock"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"88888888-8888-4888-8888-888888888888","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","visitId":"77777777-7777-4777-8777-777777777777","contactId":"66666666-6666-4666-8666-666666666666","blockType":"confirmed","source":"pm_manual","tenantConfirmationStatus":"pending","timezone":"America/Chicago","linkKey":"15151515-1515-4151-8151-151515151515","notes":"Scheduled through the Mason API.","start":"2026-09-25T14:00:00.000Z","end":"2026-09-25T16:00:00.000Z","createdAt":"2026-09-22T14:05:00.000Z","expiresAt":null,"createdBy":"External API key \"Example integration\"","supersedesBlockId":null}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"post":{"tags":["scheduling-blocks"],"operationId":"createSchedulingBlock","summary":"Book a visit appointment","description":"Books a confirmed appointment for an in-house maintenance visit with a technician, the same booking Mason's property manager agent makes when asked to schedule a visit. Recorded in the work-order activity log as this API key. The visit must be open, no visit on its work order may have a confirmed appointment or live scheduling proposal, the technician must be an active technician in this account with no overlapping appointment or blocked time, and start must be in the future. Mason records the appointment as a new confirmed scheduling block and as the work order's scheduled date; unless the technician is already the visit's only assigned technician, makes them the only one, replacing any others, and writes that assignment to the linked work order in your property management system (AppFolio assigned users, RentVine technicians) when the technician is linked to a user there; writes the scheduled date and a note to the linked work order in your property management system; and sends the technician the visit's digital ticket by text and email as their contact details allow. Mason does not message the tenant or ask the tenant to confirm the time; your property management system may send its own notifications. Inspection visits are not supported. Send start and end as exact instants with an offset. Mason converts them to the visit's scheduling timezone, which the returned block's timezone field names, and both must fall on the same calendar day there. For booking, the scheduling timezone is the property market's timezone, otherwise the work order's, otherwise the tenant's or your account's. Requires a read & write API key. Send a unique Idempotency-Key per appointment; a retry with the same key and body returns the original response instead of booking again.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Client-chosen key, unique per appointment you intend to book (for example a UUID). 1-255 printable ASCII characters. Reusing it with a different body returns 422.","schema":{"type":"string","minLength":1,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSchedulingBlockRequest"},"examples":{"book":{"summary":"Book a two-hour appointment","value":{"visitId":"77777777-7777-4777-8777-777777777777","technicianContactId":"66666666-6666-4666-8666-666666666666","start":"2026-09-25T09:00:00-05:00","end":"2026-09-25T11:00:00-05:00","notes":"Tenant prefers a morning visit."}}}}}},"responses":{"201":{"description":"The booked appointment. pmsSyncError reports a failed property management system write; the appointment exists in Mason either way. A replayed response carries the header Idempotent-Replayed: true.","content":{"application/json":{"schema":{"type":"object","description":"Scheduling-block write response.","required":["data","pmsSyncError"],"additionalProperties":false,"properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/SchedulingBlock"},{"type":"object","description":"Returned only when the appointment could not be read back; fetch it by id.","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid","description":"Mason UUID of the scheduling block."}}}]},"pmsSyncError":{"type":["string","null"],"description":"Why the change could not be written to the property management system, or null. The change is recorded in Mason either way; do not repeat it."}}},"examples":{"booked":{"summary":"Booked","value":{"data":{"id":"88888888-8888-4888-8888-888888888888","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","visitId":"77777777-7777-4777-8777-777777777777","contactId":"66666666-6666-4666-8666-666666666666","blockType":"confirmed","source":"pm_manual","tenantConfirmationStatus":"pending","timezone":"America/Chicago","linkKey":"15151515-1515-4151-8151-151515151515","notes":"Scheduled through the Mason API.","start":"2026-09-25T14:00:00.000Z","end":"2026-09-25T16:00:00.000Z","createdAt":"2026-09-22T14:05:00.000Z","expiresAt":null,"createdBy":"External API key \"Example integration\"","supersedesBlockId":null},"pmsSyncError":null}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Invalid JSON or fields, a missing Idempotency-Key, a visit or technician that does not match this account, an inspection visit, a start in the past, or a window that does not fall on one local day.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalidBody":{"summary":"Window crosses midnight","value":{"error":"start and end must fall on the same calendar day in the visit's scheduling timezone (America/Chicago), ending before midnight.","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"keyRequired":{"summary":"Missing Idempotency-Key","value":{"error":"Idempotency-Key header is required: 1-255 printable ASCII characters, unique per write.","code":"idempotency_key_required","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"409":{"description":"The visit is completed or cancelled or its work order is closed, a visit on the work order (this one or another) already has a confirmed appointment or live scheduling proposal, the technician has an overlapping appointment or blocked time, or the visit's scheduling timezone changed during the request. Nothing was booked; this response is stored under the Idempotency-Key, so retry with a new key. A request with this Idempotency-Key is still in progress or did not finish.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"technicianBooked":{"summary":"Technician already booked","value":{"error":"The technician already has an appointment or blocked time that overlaps this window.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"inProgress":{"summary":"Same Idempotency-Key still in progress","value":{"error":"A request with this Idempotency-Key is still in progress.","code":"idempotency_in_progress","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"unfinished":{"summary":"Same Idempotency-Key did not finish","value":{"error":"A previous request with this Idempotency-Key did not finish. Check whether it took effect before retrying with a new key.","code":"idempotency_request_unfinished","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"422":{"description":"This Idempotency-Key was already used with a different request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"keyReused":{"summary":"Idempotency-Key reused with a different body","value":{"error":"This Idempotency-Key was already used with a different request.","code":"idempotency_key_reused","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request failed and may have partially taken effect, in Mason or in your property management system. The same Idempotency-Key replays this failure; check the record before retrying with a new key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"writeFailed":{"summary":"Write may have partially taken effect","value":{"error":"The request failed and may have partially taken effect, in Mason or in your property management system. Check both before retrying with a new Idempotency-Key.","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/scheduling-blocks/{id}":{"get":{"tags":["scheduling-blocks"],"operationId":"getSchedulingBlock","summary":"Get one scheduling-blocks record","description":"Stored availability and appointment blocks. blockType=confirmed identifies a confirmed work window. A confirmed block and tenantConfirmationStatus are distinct facts. Range endpoints can be null for unbounded windows.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/SchedulingBlock"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"88888888-8888-4888-8888-888888888888","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","visitId":"77777777-7777-4777-8777-777777777777","contactId":"66666666-6666-4666-8666-666666666666","blockType":"confirmed","source":"pm_manual","tenantConfirmationStatus":"pending","timezone":"America/Chicago","linkKey":"15151515-1515-4151-8151-151515151515","notes":"Scheduled through the Mason API.","start":"2026-09-25T14:00:00.000Z","end":"2026-09-25T16:00:00.000Z","createdAt":"2026-09-22T14:05:00.000Z","expiresAt":null,"createdBy":"External API key \"Example integration\"","supersedesBlockId":null}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"patch":{"tags":["scheduling-blocks"],"operationId":"updateSchedulingBlock","summary":"Move, reassign, or cancel a visit appointment","description":"Moves, reassigns, or cancels a confirmed in-house visit appointment. A move or reassignment is what Mason's property manager agent does; a cancellation is the same action as unscheduling a visit in Mason's dispatcher. The body selects which: start and end and/or technicianContactId, or blockType canceled; fields from the two cannot be combined. Recorded in the work-order activity log as this API key. Requires a read & write API key. No Idempotency-Key is read.\n\nWith start and end, and optionally technicianContactId, Mason replaces the appointment: the block in the path becomes superseded and the response returns a new confirmed block with a new id (its supersedesBlockId is not set). The appointment keeps its technician unless you send technicianContactId; either way the technician must be an active technician in this account. Mason checks the technician for overlapping appointments or blocked time, records the new scheduled date on the work order and in your property management system with a note, makes the technician the visit's only assigned technician, replacing any others, and writes that assignment to the linked work order in your property management system (AppFolio assigned users, RentVine technicians) when the technician is linked to a user there, and sends the technician a new digital ticket. When the move changes the technician, only the new technician is contacted; the previous technician is not told. Mason cancels pending tenant confirmation follow-ups for the replaced appointment and does not message the tenant about the new time or ask the tenant to confirm it. Inspection visits are not supported. Send start and end as exact instants with an offset. Mason converts them to the visit's scheduling timezone, which the returned block's timezone field names, and both must fall on the same calendar day there. For a move, the scheduling timezone is the work order's timezone, otherwise the tenant's, otherwise the appointment's existing timezone.\n\nWith technicianContactId alone, Mason reassigns the visit and keeps the appointment time; the block keeps its id. The appointment must not have started and the new technician must be free at that time. The new technician replaces the visit's primary technician (other assigned technicians stay) and the assignment is synchronized to your property management system. Neither technician is notified, no digital ticket is sent, and the tenant is not messaged.\n\nWith blockType canceled, and optionally reason, Mason cancels the appointment and returns its visit to unscheduled. canceled, spelled with one L as the blockType field reads, is the only accepted blockType. Mason marks the visit's confirmed blocks canceled with your reason appended to their notes, clears the scheduled appointment on the work order in Mason, cancels pending tenant confirmation follow-ups for the appointment, and updates connected technician calendars. The scheduled date in your property management system is cleared only for an appointment that originated there (imported from AppFolio or RentVine): Mason clears it there first, and if that fails, nothing changes in Mason. An appointment booked or moved in Mason, including through POST or PATCH /scheduling-blocks, keeps its scheduled date in your property management system; clear it there if needed. The visit stays open; book it again with POST /scheduling-blocks. Mason sends no tenant or technician message, so a tenant who already confirmed the appointment is not told it was cancelled. Repeating a cancellation is safe: when the block is already canceled, the request returns 200 with the current block and nothing runs. The check is not a lock: two identical requests arriving at the same moment can both run the operation, which cancels only blocks that are still confirmed.\n\nScheduling blocks record no update timestamp, so this endpoint returns no ETag and does not evaluate If-Match. Because a moved appointment supersedes its block, repeating a move against the old block ID returns 409.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the scheduling-blocks id field.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSchedulingBlockRequest"},"examples":{"move":{"summary":"Move the appointment","value":{"start":"2026-09-26T14:00:00-05:00","end":"2026-09-26T16:00:00-05:00","notes":"Tenant asked for a later window."}},"reassign":{"summary":"Reassign the technician at the same time","value":{"technicianContactId":"66666666-6666-4666-8666-666666666666"}},"cancel":{"summary":"Cancel with a reason","value":{"blockType":"canceled","reason":"Tenant fixed the issue."}}}}}},"responses":{"200":{"description":"The appointment after the change: the replacement block for a move, the same block for a reassignment, or the same block with blockType canceled for a cancellation, including one that was already canceled. pmsSyncError reports a failed property management system write for a move or reassignment; the change is recorded in Mason either way. It is always null for a cancellation.","content":{"application/json":{"schema":{"type":"object","description":"Scheduling-block write response.","required":["data","pmsSyncError"],"additionalProperties":false,"properties":{"data":{"anyOf":[{"$ref":"#/components/schemas/SchedulingBlock"},{"type":"object","description":"Returned only when the appointment could not be read back; fetch it by id.","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid","description":"Mason UUID of the scheduling block."}}}]},"pmsSyncError":{"type":["string","null"],"description":"Why the change could not be written to the property management system, or null. The change is recorded in Mason either way; do not repeat it."}}},"examples":{"moved":{"summary":"Moved: a new block replaces the old one","value":{"data":{"id":"88888888-8888-4888-8888-000000000002","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","visitId":"77777777-7777-4777-8777-777777777777","contactId":"66666666-6666-4666-8666-666666666666","blockType":"confirmed","source":"pm_manual","tenantConfirmationStatus":"pending","timezone":"America/Chicago","linkKey":"15151515-1515-4151-8151-151515151515","notes":"Tenant asked for a later window.","start":"2026-09-26T19:00:00.000Z","end":"2026-09-26T21:00:00.000Z","createdAt":"2026-09-24T10:00:00.000Z","expiresAt":null,"createdBy":"External API key \"Example integration\"","supersedesBlockId":null},"pmsSyncError":null}},"reassigned":{"summary":"Reassigned: the block keeps its id","value":{"data":{"id":"88888888-8888-4888-8888-888888888888","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","visitId":"77777777-7777-4777-8777-777777777777","contactId":"66666666-6666-4666-8666-666666666666","blockType":"confirmed","source":"pm_manual","tenantConfirmationStatus":"pending","timezone":"America/Chicago","linkKey":"15151515-1515-4151-8151-151515151515","notes":"Scheduled through the Mason API.","start":"2026-09-25T14:00:00.000Z","end":"2026-09-25T16:00:00.000Z","createdAt":"2026-09-22T14:05:00.000Z","expiresAt":null,"createdBy":"External API key \"Example integration\"","supersedesBlockId":null},"pmsSyncError":null}},"cancelled":{"summary":"Cancelled, or already canceled: the block keeps its id","value":{"data":{"id":"88888888-8888-4888-8888-888888888888","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","visitId":"77777777-7777-4777-8777-777777777777","contactId":"66666666-6666-4666-8666-666666666666","blockType":"canceled","source":"pm_manual","tenantConfirmationStatus":"pending","timezone":"America/Chicago","linkKey":"15151515-1515-4151-8151-151515151515","notes":"Scheduled through the Mason API.\n\n[2026-09-24T12:00:00.000Z] Visit unscheduled\nReason: Tenant fixed the issue.","start":"2026-09-25T14:00:00.000Z","end":"2026-09-25T16:00:00.000Z","createdAt":"2026-09-22T14:05:00.000Z","expiresAt":null,"createdBy":"External API key \"Example integration\"","supersedesBlockId":null},"pmsSyncError":null}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Invalid JSON or fields; a body that combines move or reassignment fields (start, end, technicianContactId, notes) with blockType or reason, or a blockType other than canceled; a technician that is not an active technician in this account (the one sent, or for a move without technicianContactId the appointment's current technician); a move without technicianContactId on an appointment with no technician; an inspection visit; or a window that does not fall on one local day.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalidBody":{"summary":"start without end","value":{"error":"Invalid request body. end: start and end must be provided together","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"mixedForms":{"summary":"Move and cancel fields combined","value":{"error":"Invalid request body. Send start and end and/or technicianContactId (optionally with notes) to move or reassign the appointment, or blockType \"canceled\" (optionally with reason) to cancel it; fields from the two cannot be combined.","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No scheduling block exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"409":{"description":"For a move or reassignment: the block is not a confirmed appointment (for example superseded by an earlier move, or cancelled), is not linked to an in-house visit, the visit or work order is closed, the technician has an overlapping appointment or blocked time, the appointment has started (for a reassignment), or the visit changed during the request. For a cancellation: the block is neither confirmed nor canceled (for example superseded by a move), is not linked to a work order, or its work order is completed or cancelled. Nothing was changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"superseded":{"summary":"Block already superseded by a move","value":{"error":"Only a confirmed appointment can be changed; this block is superseded. A rescheduled appointment is replaced by a new block, so read the visit's current confirmed block.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"cancelSuperseded":{"summary":"Cancelling a block superseded by a move","value":{"error":"Only a confirmed appointment can be cancelled; this block is superseded.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"502":{"description":"For a reassignment, the technician's connected calendar could not be checked; nothing was changed. For a cancellation, your property management system could not clear the appointment, so Mason left it unchanged; or it was cleared there but Mason could not finish updating it. The error says which.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"calendarUnavailable":{"summary":"Connected calendar could not be checked","value":{"error":"The technician's connected calendar could not be checked for conflicts. Nothing was changed; retry shortly.","code":"calendar_unavailable","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"pmsUnscheduleFailed":{"summary":"Property management system could not clear a cancelled appointment","value":{"error":"The PMS could not unschedule this appointment, so Mason left it unchanged. Try again shortly.","code":"pms_write_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/units":{"get":{"tags":["units"],"operationId":"listUnit","summary":"List units","description":"Current stored units, authorized through their owning property. Vacancy and inspection fields do not provide complete historical cycles or a dated door-count denominator. Units are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. This API does not create units. PATCH /units/{id} changes only the Mason-maintained access field, which Mason does not write to your property management system; every other field is read-only here and changes only in your property management system.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"propertyId","in":"query","required":false,"description":"Exact match on propertyId. Owning Mason property ID; resolve using GET /properties/{id}.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on propertyId. Owning Mason property ID; resolve using GET /properties/{id}."}},{"name":"pmsUniqueId","in":"query","required":false,"description":"Exact match on pmsUniqueId. Stored provider unit identifier, meaningful within the owning property/account.","schema":{"type":"string","description":"Exact match on pmsUniqueId. Stored provider unit identifier, meaningful within the owning property/account."}},{"name":"isOccupied","in":"query","required":false,"description":"Exact match on isOccupied. Current stored occupancy flag.","schema":{"type":"boolean","description":"Exact match on isOccupied. Current stored occupancy flag."}},{"name":"leasingReadiness","in":"query","required":false,"description":"Exact match on leasingReadiness. Current stored leasing readiness.","schema":{"type":"string","description":"Exact match on leasingReadiness. Current stored leasing readiness."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"updatedAfter","in":"query","required":false,"description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"updatedBefore","in":"query","required":false,"description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}}],"responses":{"200":{"description":"One page of units visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching units records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/Unit"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"33333333-3333-4333-8333-333333333333","propertyId":"22222222-2222-4222-8222-222222222222","pmsUniqueId":"unit-2b","unitNumber":"2B","normalizedUnitNumber":"2B","unitFormattedAddress":"123 Example St, Unit 2B, Springfield, IL 62701","ownerInfo":null,"bedrooms":2,"bathrooms":1,"halfBathrooms":0,"squareFeet":850,"rent":145000,"isOccupied":true,"vacantSince":null,"leasingReadiness":"unknown","inspectionDeferUntil":null,"createdAt":"2026-01-05T12:00:00.000Z","updatedAt":"2026-09-20T03:15:00.000Z","access":{"gateCode":null,"lockboxCode":"2468","alarmCode":null,"notes":"Lockbox is on the back door railing."}}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/units/{id}":{"get":{"tags":["units"],"operationId":"getUnit","summary":"Get one units record","description":"Current stored units, authorized through their owning property. Vacancy and inspection fields do not provide complete historical cycles or a dated door-count denominator. Units are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. This API does not create units. PATCH /units/{id} changes only the Mason-maintained access field, which Mason does not write to your property management system; every other field is read-only here and changes only in your property management system.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404. The ETag response header identifies this version of the unit; send it as If-Match when changing it.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Unit"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"33333333-3333-4333-8333-333333333333","propertyId":"22222222-2222-4222-8222-222222222222","pmsUniqueId":"unit-2b","unitNumber":"2B","normalizedUnitNumber":"2B","unitFormattedAddress":"123 Example St, Unit 2B, Springfield, IL 62701","ownerInfo":null,"bedrooms":2,"bathrooms":1,"halfBathrooms":0,"squareFeet":850,"rent":145000,"isOccupied":true,"vacantSince":null,"leasingReadiness":"unknown","inspectionDeferUntil":null,"createdAt":"2026-01-05T12:00:00.000Z","updatedAt":"2026-09-20T03:15:00.000Z","access":{"gateCode":null,"lockboxCode":"2468","alarmCode":null,"notes":"Lockbox is on the back door railing."}}}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the unit, derived from its updatedAt. Send it as If-Match on PATCH /units/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-20T03:15:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"patch":{"tags":["units"],"operationId":"updateUnit","summary":"Update a unit's Mason-maintained access details","description":"Changes only the Mason-maintained fields listed in the request schema, as a property manager would in Mason. Nothing is written to your property management system, and fields that come from it stay read-only here and change only there. Requires a read & write API key. Sending a value a field already has is safe and needs no Idempotency-Key; nothing else runs. access is the only field. It is merged key by key into the unit's stored access details: an omitted key is left unchanged and null clears a key. Access details are not yet included in the dispatch messages Mason sends vendors and technicians; that is a separate change. Mason's phone line can read a unit's access details to a vendor who calls in and is verified as assigned to an active work order at that unit with permission to enter.\n\nOptimistic concurrency: this endpoint and GET /units/{id} return an ETag derived from the unit's updatedAt. Sending it as If-Match is strongly recommended: when the unit changed since that read, the request returns 412 before any field is applied. updatedAt advances when the unit's Mason-maintained fields change, and also when your property management system sync refreshes the record; AppFolio units are refreshed nightly, so a 412 can occur without another API client. The check is not a lock: a change made while this request is being applied is not detected.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the unit id field.","schema":{"type":"string","format":"uuid"}},{"name":"If-Match","in":"header","required":false,"description":"Strongly recommended. The ETag from your latest read of this unit; a comma-separated list is accepted. When none matches the current ETag, the request returns 412 and applies nothing. * matches any existing unit. When omitted, the changes apply regardless of intervening updates.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUnitRequest"},"examples":{"setAccess":{"summary":"Set the gate and lockbox codes with a note","value":{"access":{"gateCode":"#4821","lockboxCode":"2468","notes":"Lockbox is on the back door railing."}}},"clearCode":{"summary":"Clear the alarm code","value":{"access":{"alarmCode":null}}}}}}},"responses":{"200":{"description":"The unit after the change, or unchanged when every field already had the requested value.","headers":{"ETag":{"description":"Strong validator for this version of the unit, derived from its updatedAt. Send it as If-Match on PATCH /units/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-23T18:05:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Unit"}}},"examples":{"updated":{"summary":"Updated","value":{"data":{"id":"33333333-3333-4333-8333-333333333333","propertyId":"22222222-2222-4222-8222-222222222222","pmsUniqueId":"unit-2b","unitNumber":"2B","normalizedUnitNumber":"2B","unitFormattedAddress":"123 Example St, Unit 2B, Springfield, IL 62701","ownerInfo":null,"bedrooms":2,"bathrooms":1,"halfBathrooms":0,"squareFeet":850,"rent":145000,"isOccupied":true,"vacantSince":null,"leasingReadiness":"unknown","inspectionDeferUntil":null,"createdAt":"2026-01-05T12:00:00.000Z","updatedAt":"2026-09-23T18:05:00.000Z","access":{"gateCode":"#4821","lockboxCode":"2468","alarmCode":null,"notes":"Lockbox is on the back door railing."}}}}}}}},"400":{"description":"Invalid JSON or fields, an unrecognized field or one only your property management system can set, a body with no access field, or an access object with none of gateCode, lockboxCode, alarmCode, or notes, or with a code over 64 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"noUpdatableField":{"summary":"No updatable field","value":{"error":"Invalid request body. Provide at least one of: access","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"emptyAccess":{"summary":"Empty access object","value":{"error":"Invalid request body. access: Provide at least one of: gateCode, lockboxCode, alarmCode, notes","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No unit exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"412":{"description":"If-Match did not match the current ETag. No field was applied. The ETag header carries the current version; read the unit again before retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"staleEtag":{"summary":"The unit changed since it was read","value":{"error":"The unit changed since the If-Match version was read. Fetch it again and retry with the new ETag.","code":"precondition_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the unit, derived from its updatedAt. Send it as If-Match on PATCH /units/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-20T03:15:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/emails":{"get":{"tags":["emails"],"operationId":"listEmail","summary":"List emails","description":"Stored email content and sender provenance for your account. No trimming, classification, ingestion, or sending occurs on read. Work-order filters match the primary link only.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"masonWorkOrderId","in":"query","required":false,"description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked."}},{"name":"contactId","in":"query","required":false,"description":"Exact match on masonContactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonContactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked."}},{"name":"threadId","in":"query","required":false,"description":"Exact match on threadId. Stored provider thread or conversation ID.","schema":{"type":"string","description":"Exact match on threadId. Stored provider thread or conversation ID."}},{"name":"inBound","in":"query","required":false,"description":"Exact match on inBound. True for received email; false for sent email.","schema":{"type":"boolean","description":"Exact match on inBound. True for received email; false for sent email."}},{"name":"senderRole","in":"query","required":false,"description":"Exact match on senderRole. Recorded sender role; legacy values are returned unchanged.","schema":{"type":"string","description":"Exact match on senderRole. Recorded sender role; legacy values are returned unchanged."}},{"name":"source","in":"query","required":false,"description":"Exact match on source. Stored communication origin label, returned verbatim. It is attribution, not proof of delivery or a newly inferred classification.","schema":{"type":"string","description":"Exact match on source. Stored communication origin label, returned verbatim. It is attribution, not proof of delivery or a newly inferred classification."}},{"name":"provider","in":"query","required":false,"description":"Exact match on provider. Recorded communication transport provider, returned verbatim; null means none was recorded.","schema":{"type":"string","description":"Exact match on provider. Recorded communication transport provider, returned verbatim; null means none was recorded."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"sentAfter","in":"query","required":false,"description":"Inclusive lower bound on sentAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on sentAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"sentBefore","in":"query","required":false,"description":"Inclusive upper bound on sentAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on sentAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"receivedAfter","in":"query","required":false,"description":"Inclusive lower bound on receivedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on receivedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"receivedBefore","in":"query","required":false,"description":"Inclusive upper bound on receivedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on receivedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}}],"responses":{"200":{"description":"One page of emails visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching emails records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/Email"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"dddddddd-dddd-4ddd-8ddd-dddddddddddd","messageId":"msg-000000000001-example","emailMessageId":"<owner-update-1042@mail.example.com>","threadId":"thread-000000000001-example","inBound":false,"from":"maintenance@pm.example.com","to":["owner@example.com"],"cc":null,"subject":"Work order 1042-1 at 123 Example St: work is proceeding","snippet":"The estimate for the kitchen faucet repair was approved.","bodyText":"Hello,\n\nThe estimate for the kitchen faucet repair at 123 Example St was approved and work is proceeding.","trimmedBody":"The estimate for the kitchen faucet repair at 123 Example St was approved and work is proceeding.","source":"mason","provider":"gmail","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","relatedWorkOrderIds":null,"senderRole":"property_manager","masonContactId":"ffffffff-ffff-4fff-8fff-ffffffffffff","createdAt":"2026-09-23T16:00:00.000Z","sentAt":"2026-09-23T16:00:02.000Z","receivedAt":null,"metadata":{"sentByUserEmail":"manager@example.com"}}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/emails/{id}":{"get":{"tags":["emails"],"operationId":"getEmail","summary":"Get one emails record","description":"Stored email content and sender provenance for your account. No trimming, classification, ingestion, or sending occurs on read. Work-order filters match the primary link only.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Email"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"dddddddd-dddd-4ddd-8ddd-dddddddddddd","messageId":"msg-000000000001-example","emailMessageId":"<owner-update-1042@mail.example.com>","threadId":"thread-000000000001-example","inBound":false,"from":"maintenance@pm.example.com","to":["owner@example.com"],"cc":null,"subject":"Work order 1042-1 at 123 Example St: work is proceeding","snippet":"The estimate for the kitchen faucet repair was approved.","bodyText":"Hello,\n\nThe estimate for the kitchen faucet repair at 123 Example St was approved and work is proceeding.","trimmedBody":"The estimate for the kitchen faucet repair at 123 Example St was approved and work is proceeding.","source":"mason","provider":"gmail","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","relatedWorkOrderIds":null,"senderRole":"property_manager","masonContactId":"ffffffff-ffff-4fff-8fff-ffffffffffff","createdAt":"2026-09-23T16:00:00.000Z","sentAt":"2026-09-23T16:00:02.000Z","receivedAt":null,"metadata":{"sentByUserEmail":"manager@example.com"}}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/estimates":{"get":{"tags":["estimates"],"operationId":"listEstimate","summary":"List estimates","description":"Stored vendor estimates and recorded approval decisions. Money is cents. Legacy PM-prefixed decision fields can represent owner decisions; ownerMessageDrafted does not prove delivery.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by createdAt descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"masonWorkOrderId","in":"query","required":false,"description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonWorkOrderId. Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked."}},{"name":"vendorContactId","in":"query","required":false,"description":"Exact match on vendorContactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on vendorContactId. Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked."}},{"name":"status","in":"query","required":false,"description":"Exact match on status. Stored estimate lifecycle state.","schema":{"type":"string","description":"Exact match on status. Stored estimate lifecycle state."}},{"name":"source","in":"query","required":false,"description":"Exact match on source. Stored estimate source, such as vendor_sms, vendor_call, vendor_email, pm_inbox_email, manual, or appfolio.","schema":{"type":"string","description":"Exact match on source. Stored estimate source, such as vendor_sms, vendor_call, vendor_email, pm_inbox_email, manual, or appfolio."}},{"name":"approvedByRole","in":"query","required":false,"description":"Exact match on approvedByRole. Role recorded as approving the estimate; null means none recorded.","schema":{"type":"string","description":"Exact match on approvedByRole. Role recorded as approving the estimate; null means none recorded."}},{"name":"createdAfter","in":"query","required":false,"description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"createdBefore","in":"query","required":false,"description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on createdAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"updatedAfter","in":"query","required":false,"description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}},{"name":"updatedBefore","in":"query","required":false,"description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on updatedAt. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records. Related-record changes do not necessarily advance this timestamp."}}],"responses":{"200":{"description":"One page of estimates visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching estimates records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/Estimate"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","vendorContactId":"55555555-5555-4555-8555-555555555555","vendorName":"Example Plumbing Co.","vendorPhone":"+15555550188","status":"sent_for_approval","estimateAmount":45000,"estimateDescription":"Replace the kitchen faucet and both supply lines.","lineItems":[{"description":"Faucet","quantity":1,"unitPrice":250,"totalPrice":250},{"description":"Labor","quantity":2,"unitPrice":100,"totalPrice":200}],"estimateNotes":null,"source":"vendor_email","sourceMessageId":null,"sourceCallId":null,"approvedByRole":null,"approvedAmount":null,"approvedScope":null,"pmApprovedAt":null,"pmApprovedBy":null,"pmRejectedAt":null,"pmRejectionReason":null,"ownerMessageDrafted":false,"createdAt":"2026-09-22T19:00:00.000Z","updatedAt":"2026-09-22T19:30:00.000Z"}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/estimates/{id}":{"get":{"tags":["estimates"],"operationId":"getEstimate","summary":"Get one estimates record","description":"Stored vendor estimates and recorded approval decisions. Money is cents. Legacy PM-prefixed decision fields can represent owner decisions; ownerMessageDrafted does not prove delivery.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404. The ETag response header identifies this version of the estimate; send it as If-Match when deciding it.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Estimate"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","vendorContactId":"55555555-5555-4555-8555-555555555555","vendorName":"Example Plumbing Co.","vendorPhone":"+15555550188","status":"sent_for_approval","estimateAmount":45000,"estimateDescription":"Replace the kitchen faucet and both supply lines.","lineItems":[{"description":"Faucet","quantity":1,"unitPrice":250,"totalPrice":250},{"description":"Labor","quantity":2,"unitPrice":100,"totalPrice":200}],"estimateNotes":null,"source":"vendor_email","sourceMessageId":null,"sourceCallId":null,"approvedByRole":null,"approvedAmount":null,"approvedScope":null,"pmApprovedAt":null,"pmApprovedBy":null,"pmRejectedAt":null,"pmRejectionReason":null,"ownerMessageDrafted":false,"createdAt":"2026-09-22T19:00:00.000Z","updatedAt":"2026-09-22T19:30:00.000Z"}}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the estimate, derived from its updatedAt. Send it as If-Match on PATCH /estimates/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-22T19:30:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}},"patch":{"tags":["estimates"],"operationId":"updateEstimate","summary":"Approve or reject an estimate","description":"Approves or rejects the estimate as a property manager does in Mason, selected by status in the body. Recorded in the work-order activity log as this API key. Requires a read & write API key.\n\nWith status approved, the estimate's status becomes approved_for_work with approvedByRole (pm unless you send owner), approvedAmount (the quoted amount unless you send approvedAmount), and pmApprovedBy set to this API key's name. Mason then moves the work order to work_in_progress when its status is created, reviewed, or estimated; records the approval on the estimate in your property management system where Mason supports estimates, logging rather than failing when that write fails; unless skipReschedule is true, supersedes the work order's confirmed appointments, clears its scheduled date, and sends the tenant a scheduling link to collect availability for the follow-up visit where Mason's tenant scheduling applies to the work order; and, when approvedByRole is pm, emails the property owner that work is proceeding, unless owner outreach is paused or no owner email is on file. Send approvedByRole: owner to record an approval the property owner gave outside Mason, for example in your owner portal; Mason then sends the owner no email and otherwise handles the approval as above. Approving does not dispatch a vendor or send the vendor a message.\n\nWith status rejected, the estimate's status becomes rejected and any approval is withdrawn. Mason records the rejection on the linked AppFolio estimate, when there is one, then queues its vendor follow-up agent to tell the quoting vendor, usually within a few minutes. The agent writes that message itself, by email on the vendor's estimate or dispatch thread or by text, and shares your reason only when it is appropriate for the vendor to read. No notice is sent when Mason is stopped on the work order, the account is not live, or Mason has no contact for the vendor. Rejecting an approved estimate does not cancel a vendor dispatch.\n\nRepeating a decision is safe and needs no Idempotency-Key: when the estimate is already approved and you send approved, or already rejected and you send rejected, the request returns 200 with the current estimate and nothing runs, so no side effect repeats. approvedAmount, approvedScope, and skipReschedule are then ignored; an approved estimate keeps its recorded amount and scope. When you also send approvedByRole and the estimate is already approved with a different recorded approvedByRole, the request returns 409 instead and nothing runs; omitting approvedByRole never returns 409. The check is not a lock: two identical requests arriving at the same moment can both run the operation, as in the Mason app. Sending the opposite decision reverses the earlier one, as in Mason.\n\nOptimistic concurrency: this endpoint and GET /estimates/{id} return an ETag derived from the estimate's updatedAt. Sending it as If-Match is strongly recommended: when the estimate changed since that read, the request returns 412 before anything runs. updatedAt advances on any change to the estimate record, including changes made by Mason's own processing and property management system sync, so a 412 can occur without another API client. The check is not a lock: a change made while this request is being applied is not detected. A retry after a lost response that re-sends the If-Match value read before the first attempt returns 412, because the first attempt changed the record; re-read the record and compare its state before retrying.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the estimate id field.","schema":{"type":"string","format":"uuid"}},{"name":"If-Match","in":"header","required":false,"description":"Strongly recommended. The ETag from your latest read of this estimate; a comma-separated list is accepted. When none matches the current ETag, the request returns 412 and nothing runs. * matches any existing estimate. When omitted, the decision applies regardless of intervening updates.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEstimateRequest"},"examples":{"approve":{"summary":"Approve the quoted amount and scope","value":{"status":"approved"}},"approvePartial":{"summary":"Approve a lower amount and narrower scope","value":{"status":"approved","approvedAmount":30000,"approvedScope":"Replace the faucet only; keep the existing supply lines.","skipReschedule":true}},"approveAsOwner":{"summary":"Record the owner's approval","value":{"status":"approved","approvedByRole":"owner"}},"reject":{"summary":"Reject with a reason","value":{"status":"rejected","reason":"The quote is above our repair limit for this unit."}},"rejectAsOwner":{"summary":"Record the owner's rejection","value":{"status":"rejected","reason":"The quote is above our repair limit for this unit.","rejectedByRole":"owner"}}}}}},"responses":{"200":{"description":"The estimate after the decision, or unchanged when it was already in the requested state.","headers":{"ETag":{"description":"Strong validator for this version of the estimate, derived from its updatedAt. Send it as If-Match on PATCH /estimates/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-23T15:55:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/Estimate"}}},"examples":{"approved":{"summary":"Approved","value":{"data":{"id":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","vendorContactId":"55555555-5555-4555-8555-555555555555","vendorName":"Example Plumbing Co.","vendorPhone":"+15555550188","status":"approved_for_work","estimateAmount":45000,"estimateDescription":"Replace the kitchen faucet and both supply lines.","lineItems":[{"description":"Faucet","quantity":1,"unitPrice":250,"totalPrice":250},{"description":"Labor","quantity":2,"unitPrice":100,"totalPrice":200}],"estimateNotes":null,"source":"vendor_email","sourceMessageId":null,"sourceCallId":null,"approvedByRole":"pm","approvedAmount":45000,"approvedScope":null,"pmApprovedAt":"2026-09-23T15:55:00.000Z","pmApprovedBy":"External API key \"Example integration\"","pmRejectedAt":null,"pmRejectionReason":null,"ownerMessageDrafted":false,"createdAt":"2026-09-22T19:00:00.000Z","updatedAt":"2026-09-23T15:55:00.000Z"}}},"approvedAsOwner":{"summary":"Approved by the owner","value":{"data":{"id":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","vendorContactId":"55555555-5555-4555-8555-555555555555","vendorName":"Example Plumbing Co.","vendorPhone":"+15555550188","status":"approved_for_work","estimateAmount":45000,"estimateDescription":"Replace the kitchen faucet and both supply lines.","lineItems":[{"description":"Faucet","quantity":1,"unitPrice":250,"totalPrice":250},{"description":"Labor","quantity":2,"unitPrice":100,"totalPrice":200}],"estimateNotes":null,"source":"vendor_email","sourceMessageId":null,"sourceCallId":null,"approvedByRole":"owner","approvedAmount":45000,"approvedScope":null,"pmApprovedAt":"2026-09-23T15:55:00.000Z","pmApprovedBy":"External API key \"Example integration\"","pmRejectedAt":null,"pmRejectionReason":null,"ownerMessageDrafted":false,"createdAt":"2026-09-22T19:00:00.000Z","updatedAt":"2026-09-23T15:55:00.000Z"}}},"rejected":{"summary":"Rejected","value":{"data":{"id":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","vendorContactId":"55555555-5555-4555-8555-555555555555","vendorName":"Example Plumbing Co.","vendorPhone":"+15555550188","status":"rejected","estimateAmount":45000,"estimateDescription":"Replace the kitchen faucet and both supply lines.","lineItems":[{"description":"Faucet","quantity":1,"unitPrice":250,"totalPrice":250},{"description":"Labor","quantity":2,"unitPrice":100,"totalPrice":200}],"estimateNotes":null,"source":"vendor_email","sourceMessageId":null,"sourceCallId":null,"approvedByRole":null,"approvedAmount":null,"approvedScope":null,"pmApprovedAt":null,"pmApprovedBy":null,"pmRejectedAt":"2026-09-23T15:55:00.000Z","pmRejectionReason":"The quote is above our repair limit for this unit.","ownerMessageDrafted":false,"createdAt":"2026-09-22T19:00:00.000Z","updatedAt":"2026-09-23T15:55:00.000Z"}}}}}}},"400":{"description":"Invalid JSON or fields, a missing or unknown status, or a field that belongs to the other status (approvedAmount, approvedScope, approvedByRole, and skipReschedule are accepted only with approved; reason only with rejected).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"wrongStatusField":{"summary":"A rejection field sent with approved","value":{"error":"Invalid request body. Unrecognized key: \"reason\"","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"invalidJson":{"summary":"Malformed JSON","value":{"error":"Request body must be valid JSON.","code":"invalid_body","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"403":{"description":"The API key is read-only. Create a read & write key to use this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"readOnlyKey":{"summary":"Read-only key","value":{"error":"API token scope does not permit this operation","code":"insufficient_scope","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No estimate exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"409":{"description":"The estimate is already approved with a recorded approvedByRole different from the one you sent. Nothing ran, and the recorded approver of an approved estimate does not change. Omit approvedByRole to accept the estimate as already approved, which returns 200 unchanged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"approverConflict":{"summary":"Already approved with a different approver","value":{"error":"This estimate is already approved with approvedByRole pm. The recorded approver of an approved estimate does not change, so nothing ran.","code":"conflict","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"412":{"description":"If-Match did not match the current ETag. Nothing ran. The ETag header carries the current version; read the estimate again before retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"staleEtag":{"summary":"The estimate changed since it was read","value":{"error":"The estimate changed since the If-Match version was read. Fetch it again and retry with the new ETag.","code":"precondition_failed","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"ETag":{"description":"Strong validator for this version of the estimate, derived from its updatedAt. Send it as If-Match on PATCH /estimates/{id}. Treat it as opaque.","schema":{"type":"string"},"example":"\"2026-09-22T19:30:00.000Z\""},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/work-order-activity-logs":{"get":{"tags":["work-order-activity-logs"],"operationId":"listWorkOrderActivity","summary":"List work-order-activity-logs","description":"Allowlisted stored business events, authorized through the owning work order. Unsupported event types/versions and malformed selected payloads are excluded before pagination and from detail reads. No complete-history guarantee; absence is not proof an action never occurred. Sorts by timestamp and ID descending.\n\nFilters are combined with AND, except the documented id/ids aliases. Unknown query parameters and filter values outside a parameter's documented enum return 400. Empty values for supported filters are ignored. Results are ordered by timestamp descending, then by ID descending. Continue with nextCursor and the same filters. Cursor pagination is a stable keyset walk on that order: a row present when the traversal starts, and still matching the filters when its page is read, is neither skipped nor returned twice across pages. Each page's filters, including any date bounds, are evaluated against current values rather than a value captured when the traversal began: a row that changes before its own page is read is returned with its current values, and may newly match the filters even though it did not match when the traversal started; a row that changes after its own page has already been read is not folded into the current traversal. In both cases, the next incremental run, using this run's cutoff as its next lower bound, picks up the change.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size, normally 1–100. Defaults to 50 when omitted, zero, or not parseable as an integer; other parsed values are clamped to 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque nextCursor from the preceding page. Omit for the first page; do not construct or modify cursor values.","schema":{"type":"string"}},{"name":"masonWorkOrderId","in":"query","required":false,"description":"Exact match on masonWorkOrderId. Owning Mason work-order ID. Always present; resolve using GET /work-orders/{id}.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Exact match on masonWorkOrderId. Owning Mason work-order ID. Always present; resolve using GET /work-orders/{id}."}},{"name":"eventType","in":"query","required":false,"description":"Exact match on eventType. Allowlisted stored business event type; determines the details structure.","schema":{"type":"string","description":"Exact match on eventType. Allowlisted stored business event type; determines the details structure."}},{"name":"after","in":"query","required":false,"description":"Inclusive lower bound on timestamp. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive lower bound on timestamp. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}},{"name":"before","in":"query","required":false,"description":"Inclusive upper bound on timestamp. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Inclusive upper bound on timestamp. Use an ISO 8601 timestamp with a timezone. Invalid dates match no records."}}],"responses":{"200":{"description":"One page of work-order-activity-logs visible to the token's property management account.","content":{"application/json":{"schema":{"type":"object","description":"Paginated resource response.","required":["data","pagination"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Matching work-order-activity-logs records on this page. An empty array means no records matched.","items":{"$ref":"#/components/schemas/WorkOrderActivity"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"examples":{"page":{"summary":"A page with more results","value":{"data":[{"id":"eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","eventType":"status_changed","timestamp":"2026-09-23T16:00:00.000Z","source":"external_api","details":{"from":"reviewed","to":"work_in_progress","note":"Vendor confirmed the repair."}}],"pagination":{"hasMore":true,"nextCursor":"eyJjIjoiZXhhbXBsZSJ9"}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A query parameter is unknown, or a filter value is outside the parameter's documented enum. The message names the parameter and, for an enum, its allowed values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/work-order-activity-logs/{id}":{"get":{"tags":["work-order-activity-logs"],"operationId":"getWorkOrderActivity","summary":"Get one work-order-activity-logs record","description":"Allowlisted stored business events, authorized through the owning work order. Unsupported event types/versions and malformed selected payloads are excluded before pagination and from detail reads. No complete-history guarantee; absence is not proof an action never occurred. Sorts by timestamp and ID descending.\n\nReturns one record by its Mason UUID. Missing records and records outside the token's property management account both return 404.","parameters":[{"name":"id","in":"path","required":true,"description":"Mason UUID returned in the record id field. This is not a provider identifier or display number.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested record.","content":{"application/json":{"schema":{"type":"object","description":"Single-resource response.","required":["data"],"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/WorkOrderActivity"}}},"examples":{"record":{"summary":"One record","value":{"data":{"id":"eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee","masonWorkOrderId":"11111111-1111-4111-8111-111111111111","eventType":"status_changed","timestamp":"2026-09-23T16:00:00.000Z","source":"external_api","details":{"from":"reviewed","to":"work_in_progress","note":"Vendor confirmed the repair."}}}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"Unknown query parameters are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknownParameter":{"summary":"Unknown query parameter","value":{"error":"Unknown query parameters: updatedSince","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"404":{"description":"No record exists in this account with that ID, or the ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"notFound":{"summary":"Not found","value":{"error":"Not found","code":"not_found","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/on-call-coverage":{"get":{"tags":["on-call-coverage"],"operationId":"listOnCallCoverage","summary":"List recorded on-call coverage","description":"Returns recorded effective coverage for the requested time window, ordered by coverage start, rotation name, then row ID. Projected coverage is excluded. This endpoint returns the full requested range and does not use limit/cursor pagination or a detail endpoint. Absence of a record does not establish complete coverage history.","parameters":[{"name":"start","in":"query","required":true,"description":"Beginning of the requested time window. Use an ISO 8601 timestamp with a timezone. start must precede end and the range must not exceed 400 days.","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","required":true,"description":"End of the requested time window. Use an ISO 8601 timestamp with a timezone. start must precede end and the range must not exceed 400 days.","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Recorded coverage segments within the requested range.","content":{"application/json":{"schema":{"type":"object","description":"Recorded coverage response without pagination.","required":["data"],"additionalProperties":false,"properties":{"data":{"type":"array","description":"Coverage segments. Empty when no recorded coverage matches.","items":{"$ref":"#/components/schemas/OnCallCoverage"}}}},"examples":{"coverage":{"summary":"One recorded shift","value":{"data":[{"id":"13131313-1313-4131-8131-131313131313:2026-09-26","rotationId":"13131313-1313-4131-8131-131313131313","rotationName":"After-hours maintenance","markets":["residential"],"scheduledShiftStart":"2026-09-26T23:00:00.000Z","scheduledShiftEnd":"2026-09-27T13:00:00.000Z","coverageStart":"2026-09-26T23:00:00.000Z","coverageEnd":"2026-09-27T13:00:00.000Z","contactId":"66666666-6666-4666-8666-666666666666","contactName":"Sam Technician","contactEmail":"sam.tech@example.com","source":"rotation","overrideReason":null,"overrideRecurrence":null,"canCorrect":true,"recordStatus":"recorded","ledgerBlockId":"88888888-8888-4888-8888-888888888888","recordedAt":"2026-09-20T12:00:00.000Z","recordedBy":"manager@example.com","ledgerSource":"rotation","recordReason":null}]}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"400":{"description":"A valid start/end range of at most 400 days is required; unknown query parameters are rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalidRange":{"summary":"Missing or oversized range","value":{"error":"A valid start/end range of at most 400 days is required","code":"invalid_parameter","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"401":{"description":"Missing, malformed, invalid, inactive, or expired bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"summary":"Unknown or revoked token","value":{"error":"Invalid API token","code":"unauthorized","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}},"tokenExpired":{"summary":"Expired token","value":{"error":"API token expired","code":"token_expired","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"429":{"description":"Too many requests for this property management account. Retry after the number of seconds in the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rateLimited":{"summary":"Rate limit exceeded","value":{"error":"Rate limit exceeded","code":"rate_limited","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit window resets.","schema":{"type":"integer","minimum":1}},"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}},"500":{"description":"The request could not be completed. The response contains a generic error message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal":{"summary":"Unexpected failure","value":{"error":"Internal server error","code":"internal_error","requestId":"0b7d3c2e-5f4a-4e8b-9c1d-2a3b4c5d6e7f"}}}}},"headers":{"X-Mason-Request-Id":{"$ref":"#/components/headers/X-Mason-Request-Id"}}}}}},"/openapi.json":{"get":{"tags":["documentation"],"operationId":"getOpenApiDocument","summary":"Download this API specification","description":"Public OpenAPI 3.1 JSON document bundled with the API deployment. No token is needed. info.version is a content-derived contract revision; it changes when this specification changes. ETag supports identifying the published document. It contains documentation only and performs no customer-data reads.","security":[],"responses":{"200":{"description":"The OpenAPI document itself, without a data envelope.","content":{"application/json":{"schema":{"type":"object","description":"An OpenAPI 3.1 document. See https://spec.openapis.org/oas/v3.1.0 for the standard document structure.","additionalProperties":true}}}}}}},"/changelog":{"get":{"tags":["documentation"],"operationId":"getChangelog","summary":"Read the API changelog","description":"Public Markdown changelog of API contract changes, newest first. No token is needed. Each dated entry lists Added, Changed, Fixed, Deprecated, and Breaking changes and names the specification revision (info.version) that introduced them. ETag is derived from the changelog content. It contains documentation only and performs no customer-data reads.","security":[],"responses":{"200":{"description":"The changelog as CommonMark Markdown.","content":{"text/markdown":{"schema":{"type":"string","description":"The changelog Markdown document."}}}}}}}},"components":{"headers":{"X-Mason-Request-Id":{"description":"Identifier for this request: your own X-Request-Id when it is well-formed (8-128 letters, digits, periods, underscores, colons, or hyphens), otherwise a UUID Mason generates. Every business-data response carries it, including errors, and error bodies repeat it as requestId. Quote it when contacting Mason support. The public documentation endpoints do not carry it.","schema":{"type":"string"}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Use a Mason API key, created self-serve in Settings → API access for your property management account (see \"API keys\" above). Keys carry a read-only or read & write scope; every request stays scoped to the key's property management account regardless of scope."}},"schemas":{"Pagination":{"type":"object","properties":{"hasMore":{"type":"boolean","description":"Whether another page of matching records exists at the time of this read."},"nextCursor":{"description":"Opaque continuation token. Present only when hasMore is true; omitted on the last page. Reuse the same resource and filters with this cursor.","type":"string"}},"required":["hasMore"],"additionalProperties":false,"description":"Cursor pagination information. Fetch pages until hasMore is false. Reads are not an immutable historical snapshot."},"Error":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message for people. It can change; branch on code instead. No diagnostic stack or execution details are returned."},"code":{"type":"string","enum":["unauthorized","token_expired","insufficient_scope","account_not_live","unknown_resource","not_found","method_not_allowed","invalid_parameter","invalid_body","idempotency_key_required","idempotency_in_progress","idempotency_request_unfinished","idempotency_key_reused","precondition_failed","conflict","rate_limited","pms_write_failed","dispatch_failed","calendar_unavailable","internal_error"],"description":"Stable machine-readable error code. A code keeps its meaning once published; new codes may be added, so handle an unrecognized code by its HTTP status. Codes:\n\n- unauthorized: The Authorization header is missing or malformed, or the bearer token is unknown or revoked.\n- token_expired: The bearer token has expired. Create a new API key.\n- insufficient_scope: The API key is read-only and the request needs a read & write key.\n- account_not_live: Work-order creation becomes available once the account is live in Mason.\n- unknown_resource: The path does not name a supported resource or endpoint.\n- not_found: No record with that ID exists in this account, or the ID is not a valid UUID.\n- method_not_allowed: The resource does not support this HTTP method.\n- invalid_parameter: A query parameter is unknown or has an invalid value; the message names it.\n- invalid_body: The request body is not valid JSON, has unknown fields, or a field value was rejected; the message explains which.\n- idempotency_key_required: The write requires an Idempotency-Key header: 1-255 printable ASCII characters, unique per write.\n- idempotency_in_progress: Another request with this Idempotency-Key is still being processed. Retry later with the same key.\n- idempotency_request_unfinished: An earlier request with this Idempotency-Key did not finish. Check whether it took effect before retrying with a new key.\n- idempotency_key_reused: This Idempotency-Key was already used with a different request.\n- precondition_failed: If-Match did not match the current ETag. Nothing was applied; read the record again.\n- conflict: The change conflicts with the record's current state; the message explains the conflict.\n- rate_limited: Too many requests for this account. Retry after the Retry-After header.\n- pms_write_failed: A write to the property management system, or the Mason update that follows it, failed; the message says which.\n- dispatch_failed: The vendor or technician dispatch could not be completed; the message explains why.\n- calendar_unavailable: The technician's connected calendar could not be checked. Nothing was changed; retry shortly.\n- internal_error: The request could not be completed. For a write, the message says whether it may have partially taken effect."},"requestId":{"type":"string","description":"Identifier of this request, the same value as the X-Mason-Request-Id response header. Quote it when contacting Mason support. A replayed idempotent response carries the ID of the replaying request."}},"required":["error","code","requestId"],"additionalProperties":false,"description":"Error response returned instead of a data envelope: a human-readable message, a stable machine-readable code, and the request ID."},"OnCallCoverage":{"type":"object","properties":{"id":{"type":"string","description":"Opaque coverage-row identifier. It is not a UUID and has no detail endpoint."},"rotationId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason on-call rotation ID."},"rotationName":{"type":"string","description":"Recorded rotation name, or the current name when no snapshot is available."},"markets":{"type":"array","items":{"type":"string","description":"One coverage label."},"description":"Recorded property-class coverage labels for the rotation; an empty array means no labels are recorded."},"scheduledShiftStart":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Original scheduled shift start."},"scheduledShiftEnd":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Original scheduled shift end."},"coverageStart":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Start of this effective coverage segment within the requested range."},"coverageEnd":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"End of this effective coverage segment within the requested range."},"contactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Covered technician/contact Mason ID, when available."},"contactName":{"type":"string","description":"Recorded contact name; Unknown contact when a name is unavailable."},"contactEmail":{"anyOf":[{"type":"string","description":"Recorded contact email address."},{"type":"null"}]},"source":{"type":"string","enum":["rotation","override"],"description":"Whether coverage comes from the rotation or an override."},"overrideReason":{"anyOf":[{"type":"string","description":"Recorded business reason for an override."},{"type":"null"}]},"overrideRecurrence":{"anyOf":[{"type":"string","enum":["weekly","biweekly"]},{"type":"null"}],"description":"Override repetition; null indicates no repeating override."},"canCorrect":{"type":"boolean","description":"Whether the current application permits a correction to this coverage record; this API itself is read-only."},"recordStatus":{"type":"string","const":"recorded","description":"This endpoint returns recorded coverage only and excludes projected coverage."},"ledgerBlockId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Scheduling-block ID supporting this coverage record."},"recordedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the coverage record was created."},{"type":"null"}]},"recordedBy":{"anyOf":[{"type":"string","description":"Recorded author of the coverage record."},{"type":"null"}]},"ledgerSource":{"anyOf":[{"type":"string","description":"Stored business source of the coverage record."},{"type":"null"}]},"recordReason":{"anyOf":[{"type":"string","description":"Recorded business reason for the coverage record."},{"type":"null"}]}},"required":["id","rotationId","rotationName","markets","scheduledShiftStart","scheduledShiftEnd","coverageStart","coverageEnd","contactId","contactName","contactEmail","source","overrideReason","overrideRecurrence","canCorrect","recordStatus","ledgerBlockId","recordedAt","recordedBy","ledgerSource","recordReason"],"additionalProperties":false,"description":"One recorded on-call coverage segment. Results are ordered by coverage start, rotation name, and row ID."},"WorkOrder":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["11111111-1111-4111-8111-111111111111"]},"description":{"type":"string","description":"Recorded description of the maintenance request.","examples":["Kitchen faucet is leaking under the sink."]},"status":{"type":"string","description":"Stored work-order lifecycle status. Current values: created, reviewed, estimated, work_in_progress, duplicate, cancelled, not_handled_by_mason, work_done, closed. Historical values are returned unchanged. This is not visit or message-delivery status.","examples":["reviewed"]},"propertyAddress":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Formatted address associated with the request.","examples":["123 Example St, Springfield, IL 62701"]},"source":{"type":"string","description":"Stored intake channel, commonly pms:portal, pms:text, pms:email, pms:call, pms:system, mason:portal, mason:text, mason:email, mason:call, mason:system, or mason:recurring. It describes the origin/channel, not the requester identity. Legacy values are returned unchanged.","examples":["mason:portal"]},"workOrderType":{"type":"string","description":"Stored work category: reactive, reactive:recall, preventative, turn, recurring, misc, inspection, or an inspection subtype such as inspection:annual, inspection:move_in, inspection:move_out, inspection:pre_move_out, inspection:onboarding, inspection:semi_annual, or inspection:drive_by. Legacy values are returned unchanged.","examples":["reactive"]},"friendlyId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Human-readable Mason work-order number, when assigned. Use id for API lookups.","examples":["WO-1042"]},"isEmergency":{"type":"boolean","description":"Whether the work order is currently marked as an emergency.","examples":[false]},"hasEntryPermission":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Recorded permission to enter: true permits entry, false denies entry, and null means permission was not recorded.","examples":[true]},"propertyId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason property ID. Resolve using GET /properties/{id}.","examples":["22222222-2222-4222-8222-222222222222"]},"unitId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason unit ID, when present. Resolve using GET /units/{id}.","examples":["33333333-3333-4333-8333-333333333333"]},"tenantContactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Primary tenant Mason contact ID. Resolve using GET /contacts/{id}.","examples":["44444444-4444-4444-8444-444444444444"]},"vendorContactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Assigned vendor or in-house technician Mason contact ID. Resolve using GET /contacts/{id}; contactType may be vendor or tech."},"intakeMetadata":{"anyOf":[{"type":"object","properties":{"reportedByRole":{"description":"Recorded role of the person who reported the issue.","anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},{"type":"null"}],"description":"Allowlisted intake metadata. Only reportedByRole is public; missing or malformed role values are omitted. Null means no metadata object is recorded.","examples":[{"reportedByRole":"tenant"}]},"priority":{"anyOf":[{"type":"string","enum":["low","normal","urgent"]},{"type":"null"}],"description":"Effective attention priority. Uses the explicit user override when present, otherwise the assessment. Null means no recognized priority is recorded.","examples":["normal"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the work order was created, as an ISO 8601 timestamp.","examples":["2026-09-21T15:04:05.000Z"]},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Timestamp used by updatedAfter/updatedBefore. Includes initial import into Mason as well as stored work-order updates. Related-record changes and representation-only backfills may not advance it.","examples":["2026-09-21T15:30:00.000Z"]},"assignedUsers":{"anyOf":[{"type":"array","items":{"type":"string","description":"One assigned email address."},"description":"Stored work-order assignee email addresses; no user identities are inferred."},{"type":"null"}],"description":"Stored work-order assignee email addresses; no user identities are inferred.","examples":[["manager@example.com"]]},"requesterContactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Mason contact ID of the recorded requester; null means unresolved or not recorded.","examples":["44444444-4444-4444-8444-444444444444"]},"scopeOfWork":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored scope of the work to perform.","examples":["Replace the kitchen faucet cartridge and check the supply lines for leaks."]},"entryPermissionConditions":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored conditions attached to tenant entry permission.","examples":["Call 30 minutes before arriving; dog on site."]},"handledBy":{"type":"string","description":"Stored handling party, such as mason or property_manager; returned unchanged.","examples":["mason"]},"workOrderReview":{"anyOf":[{"type":"object","properties":{"vendorType":{"anyOf":[{"type":"string","description":"Recorded vendor service category."},{"type":"null"}]},"projectTicketCategory":{"anyOf":[{"type":"string","description":"Recorded project ticket category."},{"type":"null"}]}},"additionalProperties":false},{"type":"null"}],"description":"Selected stored business classifications; no surrounding analysis is exposed.","examples":[{"vendorType":"plumbing","projectTicketCategory":null}]},"completionAnalysis":{"anyOf":[{"type":"object","properties":{"tags":{"anyOf":[{"type":"array","items":{"type":"string","description":"One stored completion tag."},"description":"Recorded completion tags."},{"type":"null"}]},"wasAutonomous":{"anyOf":[{"type":"boolean","description":"Stored assessment of whether completion was autonomous."},{"type":"null"}]},"autonomyScore":{"anyOf":[{"type":"number","description":"Stored autonomy score; the API does not recalculate or rescale it."},{"type":"null"}]}},"additionalProperties":false},{"type":"null"}],"description":"Stored completion metrics, without recalculation or surrounding analysis."},"vendorWorkOrderRequest":{"anyOf":[{"type":"object","properties":{"scheduledConfirmedAt":{"anyOf":[{"type":"string","description":"Stored scheduling-confirmation timestamp, when present."},{"type":"null"}]}},"additionalProperties":false},{"type":"null"}],"description":"Selected stored vendor scheduling fact."},"relationships":{"type":"array","items":{"type":"object","properties":{"sourceWorkOrderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason work-order ID at the stored source end."},"targetWorkOrderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason work-order ID at the stored target end."},"relationshipType":{"type":"string","description":"Stored relationship type, such as recall or sibling; returned unchanged."}},"required":["sourceWorkOrderId","targetWorkOrderId","relationshipType"],"additionalProperties":false,"description":"One directed stored work-order relationship."},"description":"Incoming and outgoing relationships with both endpoints in your account. Empty when none qualify. Changes to these rows do not advance updatedAt.","examples":[[]]},"pms":{"anyOf":[{"type":"object","properties":{"system":{"type":"string","enum":["appfolio","rentvine","propertyware","property_meld"],"description":"Provider containing the linked work order, including Property Meld when used as an overlay."},"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason integration profile ID identifying the provider instance. Provider work-order IDs are scoped to this profile and your account."},"workOrderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Provider-native work-order ID, serialized as a string. Null when the linked provider record has no native ID. This is not a Mason UUID."},"workOrderNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Provider work-order display number, when recorded."}},"required":["system","profileId","workOrderId","workOrderNumber"],"additionalProperties":false},{"type":"null"}],"description":"Optional linked PMS identity. Null when no supported provider record is linked within your account. Provider-record changes do not necessarily advance updatedAt.","examples":[{"system":"appfolio","profileId":"12121212-1212-4121-8121-121212121212","workOrderId":"10042","workOrderNumber":"1042-1"}]}},"required":["id","description","status","propertyAddress","source","workOrderType","friendlyId","isEmergency","hasEntryPermission","propertyId","unitId","tenantContactId","vendorContactId","intakeMetadata","priority","createdAt","updatedAt","assignedUsers","requesterContactId","scopeOfWork","entryPermissionConditions","handledBy","workOrderReview","completionAnalysis","vendorWorkOrderRequest","relationships","pms"],"additionalProperties":false,"description":"Maintenance work orders belonging to your property management account. Priority describes office attention; isEmergency indicates an emergency. Returned values reflect current stored state, not a historical snapshot."},"Call":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"]},"phoneNumber":{"type":"string","description":"Phone number associated with the other party.","examples":["+15555550123"]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored readable summary of the call.","examples":["Tenant reported a leaking kitchen faucet and asked for a repair."]},"transcript":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored call transcript as text.","examples":["Tenant: Hi, my kitchen faucet is leaking under the sink.\nMason: Thanks, I have opened a work order for you."]},"callDuration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Recorded call duration in seconds.","examples":[184]},"recordingUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL of the stored call recording, when available.","examples":["https://recordings.example.com/calls/example-1042.mp3"]},"inBound":{"type":"boolean","description":"True for an incoming call; false for an outgoing call.","examples":[true]},"callStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored call outcome, such as completed, failed, busy, or no-answer.","examples":["completed"]},"callerRole":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded role of the other party, such as tenant, vendor, or property_manager. Legacy roles may occur.","examples":["tenant"]},"callType":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded business purpose of the call, such as vendor follow-up, scheduling, or work-order creation.","examples":["work_order_creation"]},"requiresAction":{"type":"boolean","description":"Whether the call is currently marked as requiring attention.","examples":[false]},"masonWorkOrderId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","examples":["11111111-1111-4111-8111-111111111111"]},"masonContactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","examples":["44444444-4444-4444-8444-444444444444"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-09-21T15:00:00.000Z"]},"endedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"When the call ended, if recorded, as an ISO 8601 timestamp.","examples":["2026-09-21T15:03:04.000Z"]},"callSid":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored call provider identifier.","examples":["CA00000000000000000000000000example"]},"relatedWorkOrderIds":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Related Mason work-order ID in your account."}},{"type":"null"}],"description":"Stored related work-order IDs whose referenced work orders belong to your account. Order and duplicates are preserved; null means no array was recorded. This does not change the primary masonWorkOrderId filter.","examples":[[]]}},"required":["id","phoneNumber","summary","transcript","callDuration","recordingUrl","inBound","callStatus","callerRole","callType","requiresAction","masonWorkOrderId","masonContactId","createdAt","endedAt","callSid","relatedWorkOrderIds"],"additionalProperties":false,"description":"Recorded phone calls scoped to your property management account. Call content and recording availability depend on the stored record."},"TextMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["cccccccc-cccc-4ccc-8ccc-cccccccccccc"]},"phoneNumber":{"type":"string","description":"Phone number associated with the other party.","examples":["+15555550123"]},"message":{"type":"string","description":"Stored message text.","examples":["A plumber will contact you today to schedule the faucet repair."]},"mediaUrls":{"anyOf":[{"type":"array","items":{"type":"string","description":"One attachment URL."},"description":"Stored URLs of media attached to this message."},{"type":"null"}],"description":"Stored URLs of media attached to this message."},"inBound":{"type":"boolean","description":"True for a received message; false for a sent message.","examples":[false]},"senderRole":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded sender role, such as tenant, vendor, owner, tech, or property_manager. Legacy roles may occur.","examples":["property_manager"]},"masonWorkOrderId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","examples":["11111111-1111-4111-8111-111111111111"]},"masonContactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","examples":["44444444-4444-4444-8444-444444444444"]},"fromNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded sending phone number.","examples":["+15555550100"]},"toNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded receiving phone number.","examples":["+15555550123"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-09-21T15:10:00.000Z"]},"source":{"type":"string","description":"Stored communication origin label, returned verbatim. It is attribution, not proof of delivery or a newly inferred classification.","examples":["mason"]},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded communication transport provider, returned verbatim; null means none was recorded.","examples":["twilio"]},"messageSid":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored SMS provider message identifier.","examples":["SM00000000000000000000000000example"]},"conversationSid":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored messaging conversation identifier."},"relatedWorkOrderIds":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Related Mason work-order ID in your account."}},{"type":"null"}],"description":"Stored related work-order IDs whose referenced work orders belong to your account. Order and duplicates are preserved; null means no array was recorded. This does not change the primary masonWorkOrderId filter."},"metadata":{"anyOf":[{"type":"object","properties":{"sentByUserEmail":{"anyOf":[{"type":"string","description":"Email address of the Mason user who sent the message, only when recorded."},{"type":"null"}]}},"additionalProperties":false},{"type":"null"}],"description":"Recorded sender provenance. Only sentByUserEmail is exposed; missing keys remain absent."}},"required":["id","phoneNumber","message","mediaUrls","inBound","senderRole","masonWorkOrderId","masonContactId","fromNumber","toNumber","createdAt","source","provider","messageSid","conversationSid","relatedWorkOrderIds","metadata"],"additionalProperties":false,"description":"Stored inbound and outbound text messages for your property management account. Work-order filtering matches the primary linked work order."},"Invoice":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["99999999-9999-4999-8999-999999999999"]},"invoiceNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Invoice number printed on the document.","examples":["INV-2041"]},"invoiceDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Invoice date as an ISO 8601 timestamp.","examples":["2026-09-24T00:00:00.000Z"]},"dueDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Invoice due date as an ISO 8601 timestamp.","examples":["2026-10-24T00:00:00.000Z"]},"totalAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Invoice total in integer cents.","examples":[24500]},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored currency code, commonly USD.","examples":["USD"]},"subtotal":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Invoice subtotal in integer cents.","examples":[22700]},"tax":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Invoice tax in integer cents.","examples":[1800]},"vendorInfo":{"anyOf":[{"type":"object","properties":{"name":{"type":"string","description":"Party or company name."},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Postal address as one line; a structured source address is joined into a single line. Null when none is recorded."},"email":{"type":"string","description":"Email address supplied on the invoice."},"phone":{"type":"string","description":"Phone number supplied on the invoice."}},"additionalProperties":{},"description":"Vendor information recorded on the invoice document."},{"type":"null"}],"description":"Vendor information recorded on the invoice document.","examples":[{"name":"Example Plumbing Co.","email":"billing@plumbing.example.com","phone":"+15555550188"}]},"billToInfo":{"anyOf":[{"type":"object","properties":{"name":{"type":"string","description":"Party or company name."},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Postal address as one line; a structured source address is joined into a single line. Null when none is recorded."},"email":{"type":"string","description":"Email address supplied on the invoice."},"phone":{"type":"string","description":"Phone number supplied on the invoice."}},"additionalProperties":{},"description":"Bill-to party recorded on the invoice document."},{"type":"null"}],"description":"Bill-to party recorded on the invoice document.","examples":[{"name":"Example Property Management"}]},"items":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"description":{"type":"string","description":"Description of the billed product or service."},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Quantity as recorded on the invoice, as a number. Null when the stored value is not a number. Examples: \"N/A\" or \"2 hrs\"."},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price per unit as a number in the document's own units, so a stored \"$1,234.50\" is 1234.5; unlike top-level totalAmount, it is not converted to cents. Null when the stored value is not a number."},"totalPrice":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Extended line amount as a number in the document's own units, not converted to cents. Null when the stored value is not a number."}},"additionalProperties":{},"description":"One recorded invoice line item. Amounts are numbers in the document's own units, not necessarily cents."},"description":"Stored invoice line items. Quantities and amounts are numbers read from the recorded values; amounts are not converted to cents."},{"type":"null"}],"description":"Stored invoice line items. Quantities and amounts are numbers read from the recorded values; amounts are not converted to cents.","examples":[[{"description":"Replace kitchen faucet cartridge","quantity":1,"unitPrice":147,"totalPrice":147},{"description":"Labor","quantity":1,"unitPrice":80,"totalPrice":80}]]},"workOrderNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Human-readable work-order number associated with the invoice.","examples":["1042-1"]},"masonWorkOrderId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","examples":["11111111-1111-4111-8111-111111111111"]},"confidence":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored extraction confidence or processing classification. Common values include high, medium, low, failed, failed_with_partial_data, and no_pdf_attachments.","examples":["high"]},"isInvoice":{"type":"boolean","description":"Whether this record is classified as an invoice.","examples":[true]},"additionalNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Additional notes recorded with the invoice."},"isRecurring":{"type":"boolean","description":"Whether the invoice was classified as recurring.","examples":[false]},"recurringDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded description of the recurring charge."},"matchedVendor":{"anyOf":[{"type":"object","properties":{"entityId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Identifier in the connected property management system, as a string; meaningful only within that account. Null when none is recorded."},"confidence":{"type":"string","description":"Stored confidence in this match, when present."},"matchType":{"type":"string","description":"Recorded matching category, when present."},"pmsUrl":{"anyOf":[{"type":"string","description":"Link to the matched record in the connected property management system."},{"type":"null"}]},"vendorId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Vendor identifier in the connected system, as a string. Null when none is recorded."},"vendorName":{"type":"string","description":"Matched vendor name."},"companyName":{"type":"string","description":"Matched vendor company name."},"telephone":{"type":"string","description":"Matched vendor phone number."},"email":{"type":"string","description":"Matched vendor email address."},"defaultBillSplitAccount":{"anyOf":[{"type":"string","description":"Default ledger account identifier for vendor bill splits."},{"type":"null"}]},"defaultMarkupDiscount":{"anyOf":[{"type":"string","description":"Default markup or discount setting from the connected system."},{"type":"null"}]},"vendorInfo":{"anyOf":[{"type":"object","properties":{"name":{"type":"string","description":"Party or company name."},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Postal address as one line; a structured source address is joined into a single line. Null when none is recorded."},"email":{"type":"string","description":"Email address supplied on the invoice."},"phone":{"type":"string","description":"Phone number supplied on the invoice."}},"additionalProperties":{},"description":"Invoice party information as recorded on the document. Keys may be missing."},{"type":"null"}]}},"additionalProperties":{},"description":"Vendor matched to the invoice. Provider-specific keys may be present; this is a stored snapshot, not a fresh vendor lookup."},{"type":"null"}],"description":"Vendor matched to the invoice. Provider-specific keys may be present; this is a stored snapshot, not a fresh vendor lookup.","examples":[{"vendorId":"778","vendorName":"Example Plumbing Co.","confidence":"high"}]},"matchedProperty":{"anyOf":[{"type":"object","properties":{"entityId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Identifier in the connected property management system, as a string; meaningful only within that account. Null when none is recorded."},"confidence":{"type":"string","description":"Stored confidence in this match, when present."},"matchType":{"type":"string","description":"Recorded matching category, when present."},"pmsUrl":{"anyOf":[{"type":"string","description":"Link to the matched record in the connected property management system."},{"type":"null"}]},"propertyId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Property identifier in the connected system, as a string. Null when none is recorded."},"buildingName":{"type":"string","description":"Matched property or building name."},"fullAddress":{"type":"string","description":"Formatted property address."},"attachedPortfolio":{"anyOf":[{"type":"string","description":"Portfolio associated with the matched property."},{"type":"null"}]},"buildingAbbreviation":{"anyOf":[{"type":"string","description":"Short building label."},{"type":"null"}]},"propertyInfo":{"description":"Provider-specific property snapshot; no uniform nested schema is guaranteed."}},"additionalProperties":{},"description":"Property matched to the invoice. Stored provider snapshot; optional keys vary by provider and record age."},{"type":"null"}],"description":"Property matched to the invoice. Stored provider snapshot; optional keys vary by provider and record age.","examples":[{"propertyId":"3301","fullAddress":"123 Example St, Springfield, IL 62701","confidence":"high"}]},"matchedWorkOrder":{"anyOf":[{"type":"object","properties":{"entityId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Identifier in the connected property management system, as a string; meaningful only within that account. Null when none is recorded."},"confidence":{"type":"string","description":"Stored confidence in this match, when present."},"matchType":{"type":"string","description":"Recorded matching category, when present."},"pmsUrl":{"anyOf":[{"type":"string","description":"Link to the matched record in the connected property management system."},{"type":"null"}]},"workOrderId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Matched provider work-order identifier, as a string. Null when none is recorded."},"workOrderNumber":{"type":"string","description":"Human-readable provider work-order number."},"appFolioServiceRequestId":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"AppFolio service-request identifier used to link to the work order."},"status":{"type":"string","description":"Stored status of the matched work order."},"type":{"anyOf":[{"type":"string","description":"Stored work-order type."},{"type":"null"}]},"source":{"anyOf":[{"type":"string","description":"Recorded source of the matched work order."},{"type":"null"}]},"isVacant":{"anyOf":[{"type":"boolean","description":"Whether the location was recorded as vacant."},{"type":"null"}]},"filename":{"type":"string","description":"Associated document filename."},"description":{"type":"string","description":"Description of the matched work."},"propertyAddress":{"type":"string","description":"Address associated with the work."},"workOrderGrammaticalSummary":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Readable summary of the work order. Null when none is recorded."},"doNotExceed":{"anyOf":[{"type":"string","description":"Stored spending limit from the connected system."},{"type":"null"}]},"stickyNote":{"anyOf":[{"type":"string","description":"Recorded work-order note."},{"type":"null"}]},"workStatus":{"anyOf":[{"type":"string","description":"Provider work status."},{"type":"null"}]},"tasks":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Provider task identifier."},"date":{"type":"string","description":"Recorded task date."},"delegated":{"type":"array","items":{"type":"string","description":"Delegate name or identifier."},"description":"People delegated to the task."},"description":{"type":"string","description":"Task description."},"isCompleted":{"type":"boolean","description":"Whether the task was completed."}},"additionalProperties":{},"description":"A task in the matched provider work order."}},{"type":"null"}],"description":"Stored provider tasks, when available."},"warnings":{"type":"array","items":{"description":"A recorded business warning associated with the match; shape varies by provider."},"description":"Warnings associated with the matched work order."},"upAndUpBillChecklist":{"description":"Provider-specific bill review checklist, when available."},"masonUrl":{"anyOf":[{"type":"string","description":"Link to the work order in Mason."},{"type":"null"}]},"workOrderInfo":{"description":"Provider-specific work-order snapshot; keys vary by integration."}},"additionalProperties":{},"description":"Work order matched to the invoice. Identifiers here belong to the connected system; use the invoice masonWorkOrderId for Mason API joins."},{"type":"null"}],"description":"Work order matched to the invoice. Identifiers here belong to the connected system; use the invoice masonWorkOrderId for Mason API joins.","examples":[{"workOrderId":"10042","workOrderNumber":"1042-1","confidence":"high"}]},"emailMessageId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored source email identifier; it is not necessarily a Mason record UUID.","examples":["<invoice-2041@mail.example.com>"]},"emailSender":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Source email sender.","examples":["billing@plumbing.example.com"]},"emailSubject":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Source email subject.","examples":["Invoice INV-2041 for 123 Example St"]},"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Primary document filename.","examples":["INV-2041.pdf"]},"pdfBlobUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL of the primary document. Despite this field name, the document can be an image or another supported attachment type; inspect attachment mimeType.","examples":["https://files.example.com/invoices/INV-2041.pdf"]},"attachments":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"filename":{"type":"string","description":"Attachment filename."},"mimeType":{"type":"string","description":"Content type, such as application/pdf or image/jpeg."},"size":{"type":"number","description":"File size in bytes, when recorded."},"blobUrl":{"anyOf":[{"type":"string","description":"URL for the stored attachment."},{"type":"null"}]},"contentId":{"anyOf":[{"type":"string","description":"Email content identifier for an inline attachment."},{"type":"null"}]},"isInline":{"anyOf":[{"type":"boolean","description":"Whether the attachment was displayed inline in the email."},{"type":"null"}]},"kind":{"type":"string","description":"Recorded attachment category."},"adjustment":{"type":"object","properties":{"originalTotalAmountCents":{"anyOf":[{"type":"number","description":"Original invoice total in cents."},{"type":"null"}]},"approvedTotalAmountCents":{"type":"number","description":"Approved replacement invoice total in cents."},"adjustmentAmountCents":{"anyOf":[{"type":"number","description":"Adjustment amount in cents."},{"type":"null"}]},"reason":{"anyOf":[{"type":"string","description":"Business reason for the adjustment."},{"type":"null"}]},"approvedBy":{"anyOf":[{"type":"string","description":"Recorded approver."},{"type":"null"}]},"approvedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the adjustment was approved."},"originalPdfBlobUrl":{"anyOf":[{"type":"string","description":"Original document URL."},{"type":"null"}]},"originalFilename":{"anyOf":[{"type":"string","description":"Original document filename."},{"type":"null"}]}},"additionalProperties":{},"description":"Recorded adjustment to an invoice document."},"pdfEdit":{"type":"object","properties":{"originalPdfBlobUrl":{"anyOf":[{"type":"string","description":"Original document URL."},{"type":"null"}]},"originalFilename":{"anyOf":[{"type":"string","description":"Original document filename."},{"type":"null"}]},"editedPdfBlobUrl":{"type":"string","description":"Edited document URL."},"editedFilename":{"type":"string","description":"Edited document filename."},"editedBy":{"anyOf":[{"type":"string","description":"Recorded editor."},{"type":"null"}]},"editedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the document was edited."},"reason":{"anyOf":[{"type":"string","description":"Business reason for the edit."},{"type":"null"}]},"editCount":{"type":"number","description":"Number of recorded document edits."}},"additionalProperties":{},"description":"Recorded edit to the invoice document."},"invoiceTemplate":{"description":"Stored invoice presentation metadata; optional keys vary by document format."},"sourceInvoiceSplit":{"description":"Stored relationship to a source invoice split across properties; optional keys vary by split format."}},"additionalProperties":{},"description":"An invoice attachment. Additional document-editing or source metadata may be present on historical records."},"description":"Stored attachment records; optional metadata varies by document."},{"type":"null"}],"description":"Stored attachment records; optional metadata varies by document.","examples":[[{"filename":"INV-2041.pdf","mimeType":"application/pdf","size":48213,"blobUrl":"https://files.example.com/invoices/INV-2041.pdf"}]]},"status":{"type":"string","description":"Stored invoice processing status, such as pending, processed, incomplete, not_invoice, reprocessing, failed, failed_with_partial_data, or no_pdf_attachments.","examples":["processed"]},"reviewed":{"type":"boolean","description":"Whether the invoice has been marked reviewed by the office/accounting process.","examples":[false]},"reviewReason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded review disposition, commonly bill_created, completed_outside_mason, duplicate, not_an_invoice, or archived."},"pmApproved":{"type":"boolean","description":"Whether the invoice is marked approved.","examples":[false]},"pmApprovedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Recorded approval timestamp."},"pmApprovedBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded approving user identifier, typically an email address."},"pmRejected":{"type":"boolean","description":"Whether the invoice is marked rejected.","examples":[false]},"pmRejectedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Recorded rejection timestamp."},"pmRejectionReason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded business reason for rejection."},"pmsUploadedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"When bill upload to the connected property management system was recorded."},"pmsBillUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Link to the bill created in the connected property management system."},"workDoneDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded description of the completed work used for billing.","examples":["Replaced the kitchen faucet cartridge."]},"selectedGlAccountId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Selected ledger account identifier in the connected system.","examples":["6400"]},"selectedTerms":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored payment terms selected for billing.","examples":["Net 30"]},"selectedMarkupPercentage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Markup selected for billing, as a number (percent; 10 means ten percent). It is a signed adjustment and can be negative. Null when no markup is selected or the stored value is not a decimal number with an optional trailing percent sign.","examples":[10]},"selectedMarkupAccountId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Selected ledger account identifier for markup.","examples":["4800"]},"selectedDiscountPercentage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Discount selected for billing, as a number (percent; 10 means ten percent). Null when no discount is selected, the selection was cleared, or the stored value is not a decimal number with an optional trailing percent sign."},"shareInvoiceWithOwner":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the invoice is marked to be shared with the owner; this flag alone does not prove delivery.","examples":[false]},"suggestedBillSplits":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"description":{"type":"string","description":"Description for this allocation."},"amount":{"type":"string","description":"Stored allocation amount as a decimal string."},"glAccountId":{"anyOf":[{"type":"string","description":"Provider ledger account identifier."},{"type":"null"}]}},"additionalProperties":{},"description":"One recorded bill allocation."},"description":"Recorded proposed bill allocations, when available."},{"type":"null"}],"description":"Recorded proposed bill allocations, when available."},"tenantChargeSignal":{"anyOf":[{"type":"object","properties":{"recommended":{"type":"boolean","description":"Whether a resident charge is recommended."},"reason":{"anyOf":[{"type":"string","description":"Business explanation for the recommendation."},{"type":"null"}]},"glSuggestion":{"type":"string","description":"Suggested ledger category for the resident charge."}},"additionalProperties":{},"description":"Recorded recommendation about charging the resident."},{"type":"null"}],"description":"Recorded recommendation about charging the resident."},"needsReview":{"type":"boolean","description":"Whether the recorded validation result requires review.","examples":[false]},"agreementValidation":{"anyOf":[{"type":"object","properties":{"isValid":{"type":"boolean","description":"Whether the recorded invoice checks passed."},"confidence":{"type":"string","description":"Confidence in the recorded validation result; commonly high, medium, or low."},"reasoning":{"type":"string","description":"Recorded business explanation of the validation result."},"conflicts":{"type":"array","items":{"type":"string","description":"One conflict or review reason."},"description":"Recorded disagreements or review reasons."},"rematchAttempt":{"anyOf":[{"type":"object","properties":{"attempted":{"type":"boolean","description":"Whether rematching was attempted."},"succeeded":{"type":"boolean","description":"Whether rematching succeeded."},"originalWorkOrderId":{"type":"string","description":"Original work-order reference."},"newWorkOrderId":{"type":"string","description":"Replacement work-order reference."},"reason":{"type":"string","description":"Recorded explanation for rematching."}},"additionalProperties":{},"description":"Recorded attempt to match the invoice to a different work order."},{"type":"null"}]},"alreadyProcessed":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Recorded disposition, such as duplicate or completed_outside_mason."},"duplicateOfInvoiceId":{"anyOf":[{"type":"string","description":"Mason invoice ID of the existing invoice."},{"type":"null"}]},"explanation":{"anyOf":[{"type":"string","description":"Business explanation for this disposition."},{"type":"null"}]}},"additionalProperties":{},"description":"Recorded determination that the invoice had already been handled."},{"type":"null"}]},"duplicateResolution":{"anyOf":[{"type":"object","properties":{"action":{"type":"string","description":"Recorded decision: keep_existing, keep_incoming, or keep_both."},"existingInvoiceId":{"type":"string","description":"Mason invoice ID considered during the decision."},"explanation":{"type":"string","description":"Business explanation for the duplicate decision."}},"additionalProperties":{},"description":"Recorded resolution of a duplicate invoice."},{"type":"null"}]},"invoiceSplitSource":{"description":"Stored multi-property source-document and allocation information, when present."},"invoiceAllocationSource":{"description":"Stored source-document allocation information, when present."}},"additionalProperties":{},"description":"Stored invoice validation result describing whether the vendor, property, and work order agree. The explanation is also displayed in the invoice review UI. Optional historical processing metadata may be present."},{"type":"null"}],"description":"Stored invoice validation result describing whether the vendor, property, and work order agree. The explanation is also displayed in the invoice review UI. Optional historical processing metadata may be present.","examples":[{"isValid":true,"confidence":"high"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-09-24T17:00:00.000Z"]},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When this record was last updated, as an ISO 8601 timestamp. Changes to related records do not necessarily advance this value.","examples":["2026-09-24T17:05:00.000Z"]}},"required":["id","invoiceNumber","invoiceDate","dueDate","totalAmount","currency","subtotal","tax","vendorInfo","billToInfo","items","workOrderNumber","masonWorkOrderId","confidence","isInvoice","additionalNotes","isRecurring","recurringDescription","matchedVendor","matchedProperty","matchedWorkOrder","emailMessageId","emailSender","emailSubject","filename","pdfBlobUrl","attachments","status","reviewed","reviewReason","pmApproved","pmApprovedAt","pmApprovedBy","pmRejected","pmRejectedAt","pmRejectionReason","pmsUploadedAt","pmsBillUrl","workDoneDescription","selectedGlAccountId","selectedTerms","selectedMarkupPercentage","selectedMarkupAccountId","selectedDiscountPercentage","shareInvoiceWithOwner","suggestedBillSplits","tenantChargeSignal","needsReview","agreementValidation","createdAt","updatedAt"],"additionalProperties":false,"description":"Stored invoices, matching results, and review/billing state. Top-level monetary amounts are integer cents. Nested document data is returned as stored, except that line-item quantities and amounts, matched-record identifiers, and party addresses are returned in their documented types; a stored value that cannot be read as that type is null."},"Contact":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["44444444-4444-4444-8444-444444444444"]},"name":{"type":"string","description":"Contact display name.","examples":["Jordan Example"]},"phoneNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded contact phone number.","examples":["+15555550123"]},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded contact email address.","examples":["jordan@example.com"]},"contactType":{"type":"string","description":"Contact category, such as tenant, vendor, owner, tech, or property_manager.","examples":["tenant"]},"isActive":{"type":"boolean","description":"Whether the contact is marked active.","examples":[true]},"preferredContactMethod":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The contact's preferred communication method: phone, text, or email; null when none is recorded. Historical values are returned unchanged. Maintained in Mason and not written to your property management system; change it with PATCH /contacts/{id}.","examples":["text"]},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The contact's preferred language as a language code, such as en (English), es (Spanish), pt, pa, or zh, optionally with subtags such as en-US; null when none is recorded. Historical values are returned unchanged. Maintained in Mason and not written to your property management system; change it with PATCH /contacts/{id}.","examples":["en"]},"pmsUniqueId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Contact identifier from the connected property management system; scoped to your account.","examples":["tenant-5521"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-01-10T12:00:00.000Z"]},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When this record was last updated, as an ISO 8601 timestamp. Changes to related records do not necessarily advance this value.","examples":["2026-09-21T15:10:00.000Z"]},"sentiment":{"anyOf":[{"type":"object","properties":{"value":{"type":"string","enum":["positive","neutral","frustrated"],"description":"Latest inferred contact sentiment: positive, neutral, or frustrated."},"score":{"type":"number","enum":[1,2,3,4],"description":"1 = strongly frustrated; 2 = negative; 3 = neutral/mixed; 4 = positive. Not a customer-submitted star rating."},"confidence":{"type":"string","enum":["low","medium","high"],"description":"Confidence recorded with the assessment."},"assessedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$","description":"When the latest contact assessment was recorded, as an ISO 8601 timestamp."},"sourceWorkOrderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason work-order ID that supplied the evidence for this contact assessment, within your account."}},"required":["value","score","confidence","assessedAt","sourceWorkOrderId"],"additionalProperties":false},{"type":"null"}],"description":"Latest stored contact-level sentiment assessment, not per-work-order rating history. Null when absent, invalid, or its source work order is unavailable within your account. Summary, evidence, and other internal context are not exposed.","examples":[{"value":"positive","score":4,"confidence":"medium","assessedAt":"2026-09-21T16:00:00.000Z","sourceWorkOrderId":"11111111-1111-4111-8111-111111111111"}]},"stopAllComms":{"type":"boolean","description":"Whether Mason-initiated texts, emails, calls, and group-chat adds to this contact are blocked. The block also covers other contacts in your account with the same phone number or email address, and it does not stop inbound replies from the contact. Maintained in Mason and not written to your property management system; change it with PATCH /contacts/{id}.","examples":[false]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Internal notes about this contact, shown to the Mason team and Mason's agents and never to the contact; null when none are recorded. Maintained in Mason and not written to your property management system; change them with PATCH /contacts/{id}.","examples":["Works nights; text before 10 AM only for emergencies."]}},"required":["id","name","phoneNumber","email","contactType","isActive","preferredContactMethod","language","pmsUniqueId","createdAt","updatedAt","sentiment","stopAllComms","notes"],"additionalProperties":false,"description":"People and businesses in your property management account. Hydrate contact references with a detail request or the id/ids filters, even when the contact predates your incremental sync window. Tenant (resident), owner, and vendor contacts are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. Technician, property-manager, emergency, and unidentified contacts are maintained in Mason. POST /contacts creates vendor contacts only: in RentVine or AppFolio first when your account is connected to one, otherwise in Mason alone. PATCH /contacts/{id} changes only the Mason-maintained fields preferredContactMethod, language, stopAllComms, and notes, which Mason does not write to your property management system; every other field is read-only here, and fields your property management system provides change only there."},"Visit":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["77777777-7777-4777-8777-777777777777"]},"logDate":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Date represented by this visit, serialized as an ISO 8601 timestamp.","examples":["2026-09-25T00:00:00.000Z"]},"controlNumber":{"type":"string","description":"Legacy visit reference. Use id for API lookups.","examples":["CN-1042"]},"location":{"type":"string","description":"Recorded location of the work.","examples":["123 Example St, Unit 2B, Springfield, IL 62701"]},"problem":{"type":"string","description":"Recorded description of the issue.","examples":["Kitchen faucet is leaking under the sink."]},"instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Dispatch instructions for the technician.","examples":["Replace the faucet cartridge and check the supply lines."]},"priority":{"type":"string","description":"Recorded visit priority, commonly urgent, normal, or low.","examples":["normal"]},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded disposition, commonly Complete, Still Working, Canceled, Estimate, or an empty string.","examples":["Still Working"]},"noteReviewed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the office has reviewed the recorded work notes; null means not recorded.","examples":[false]},"initialRouting":{"type":"array","items":{"type":"string","description":"One routing technician name."},"description":"Legacy routing technician names. Use assignedTechs for contact identifiers.","examples":[[]]},"workNotes":{"anyOf":[{"type":"object","properties":{"hoursWorked":{"type":"number","description":"Hours recorded in these notes; not a complete per-technician labor ledger."},"comments":{"type":"string","description":"Work notes or technician comments."},"timestamp":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the notes were recorded."},"notBillable":{"type":"boolean","description":"Whether these notes mark the work as not billable."}},"additionalProperties":{},"description":"Recorded work notes. Keys may be absent on older records."},{"type":"null"}],"description":"Recorded work notes. Keys may be absent on older records."},"estimate":{"anyOf":[{"type":"object","properties":{"totalAmount":{"type":"number","description":"Total quoted amount in the stored representation."},"laborItems":{"type":"array","items":{"type":"object","properties":{"description":{"type":"string","description":"Labor description."},"cost":{"type":"number","description":"Recorded labor cost."}},"additionalProperties":{},"description":"An estimated labor item."},"description":"Estimated labor items."},"materialItems":{"type":"array","items":{"type":"object","properties":{"description":{"type":"string","description":"Material description."},"cost":{"type":"number","description":"Recorded material cost."}},"additionalProperties":{},"description":"An estimated material item."},"description":"Estimated material items."},"notes":{"type":"string","description":"Estimate notes."},"audioUrl":{"type":"string","description":"Associated audio recording URL."},"timestamp":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the estimate was recorded."}},"additionalProperties":{},"description":"Recorded visit estimate. Amounts retain their stored representation."},{"type":"null"}],"description":"Recorded visit estimate. Amounts retain their stored representation."},"activity":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string","description":"Recorded event label, such as confirmed, assigned, final_disposition_set, notes_added, or printed."},"timestamp":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the event was recorded."}},"additionalProperties":{},"description":"A stored visit activity entry. Other business keys may be present."},"description":"Stored visit activity entries; this is not a complete work-order history.","examples":[[{"event":"assigned","timestamp":"2026-09-22T14:00:00.000Z"}]]},"assignedTechs":{"type":"array","items":{"type":"string","description":"Mason contact ID for an assigned technician."},"description":"Assigned technician Mason contact IDs. These are assignments, not evidence of hours worked.","examples":[["66666666-6666-4666-8666-666666666666"]]},"masonWorkOrderId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","examples":["11111111-1111-4111-8111-111111111111"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-09-22T14:00:00.000Z"]},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When this record was last updated, as an ISO 8601 timestamp. Changes to related records do not necessarily advance this value.","examples":["2026-09-25T18:30:00.000Z"]},"techHours":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason applied-hours record ID."},"techContactId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason technician contact ID."},"workedOn":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"Service date, in the visit timezone."},"hours":{"type":"string","description":"Applied hours as a decimal string, preserving database precision. Use this field once when totaling labor."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the applied-hours record was created."},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the applied-hours record was last updated."}},"required":["id","techContactId","workedOn","hours","createdAt","updatedAt"],"additionalProperties":false,"description":"One canonical applied-hours record."},"description":"Recorded applied labor hours. Related-row edits do not necessarily advance the visit updatedAt; refetch the relevant cohort.","examples":[[{"id":"14141414-1414-4141-8141-141414141414","techContactId":"66666666-6666-4666-8666-666666666666","workedOn":"2026-09-25","hours":"1.50","createdAt":"2026-09-25T18:30:00.000Z","updatedAt":"2026-09-25T18:30:00.000Z"}]]},"techClockSessions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason clock-session record ID."},"techContactId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason technician contact ID."},"clockedInAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Recorded clock-in timestamp."},"clockedOutAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Recorded clock-out timestamp; null while open."},{"type":"null"}]},"workedOn":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"Recorded service date in the session timezone."},"timezone":{"type":"string","description":"Stored IANA timezone for the service date."},"pausedSeconds":{"type":"number","description":"Stored accumulated seconds for completed pauses."}},"required":["id","techContactId","clockedInAt","clockedOutAt","workedOn","timezone","pausedSeconds"],"additionalProperties":false,"description":"One recorded technician clock session."},"description":"Supporting clock observations. Do not add their duration to techHours: closed sessions may already be applied there. No attendance or extra labor totals are inferred.","examples":[[]]}},"required":["id","logDate","controlNumber","location","problem","instructions","priority","status","noteReviewed","initialRouting","workNotes","estimate","activity","assignedTechs","masonWorkOrderId","createdAt","updatedAt","techHours","techClockSessions"],"additionalProperties":false,"description":"Maintenance visit records. Assigned technicians describe assignment, not completed labor. Nested JSON is returned as stored; changes to related records do not necessarily update this record timestamp."},"Property":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["22222222-2222-4222-8222-222222222222"]},"formattedAddress":{"type":"string","description":"Formatted property address.","examples":["123 Example St, Springfield, IL 62701"]},"address":{"type":"string","description":"First address line.","examples":["123 Example St"]},"address2":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Second address line."},"city":{"type":"string","description":"City.","examples":["Springfield"]},"state":{"type":"string","description":"State or region.","examples":["IL"]},"zip":{"type":"string","description":"Postal code.","examples":["62701"]},"isActive":{"type":"boolean","description":"Whether the property is marked active.","examples":[true]},"multiUnit":{"type":"boolean","description":"Whether the property is marked as containing multiple units.","examples":[true]},"ownerInfo":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Owner display name."},"email":{"type":"string","description":"Owner email address."},"homePhone":{"type":"string","description":"Home phone number."},"workPhone":{"type":"string","description":"Work phone number."},"mobilePhone":{"type":"string","description":"Mobile phone number."},"otherPhone":{"type":"string","description":"Additional phone number."},"ownershipPercentage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Ownership percentage as a number (percent; 50 means fifty percent), so a stored \"50.00%\" is 50. Null when the stored value is not a number."},"isPrimary":{"type":"boolean","description":"Whether this is the primary owner."}},"additionalProperties":{},"description":"Stored property owner information. Keys vary by property management system."},"description":"Stored property owner records; null means no ownership data was recorded, while an empty array contains no listed owners."},{"type":"null"}],"description":"Stored property owner records; null means no ownership data was recorded, while an empty array contains no listed owners.","examples":[[{"name":"Example Holdings LLC","email":"owner@example.com","isPrimary":true}]]},"propertyDetails":{"anyOf":[{"type":"object","properties":{"market":{"type":"string","description":"Stored market label; may be absent."},"lat":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stored latitude as a number, when available. Null when the stored value is not a number."},"long":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stored longitude as a number, when available. Null when the stored value is not a number."},"originalPropertyWareEntityId":{"type":"string","description":"Original PropertyWare property identifier."},"buildingName":{"type":"string","description":"Building display name."},"buildingType":{"type":"string","description":"Building classification supplied by the provider."},"yearBuilt":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Year built as a number. Null when the stored value is not a number."},"multiUnit":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Provider multi-unit flag as a boolean; use the top-level multiUnit boolean for the Mason value. Stored Yes/No, true/false, and 1/0 values are converted; other values are null."},"propertyType":{"type":"string","description":"Provider property classification."},"parcelNumber":{"type":"string","description":"Parcel identifier."},"numberOfFloors":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Number of floors as a number. Null when the stored value is not a number."},"readyToLease":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Provider leasing-readiness flag as a boolean. Stored Yes/No, true/false, and 1/0 values are converted; other values are null."}},"additionalProperties":{},"description":"Stored property details. Available keys depend on the connected property management system, and additional keys may be present; documented keys have the types shown."},{"type":"null"}],"description":"Stored property details. Available keys depend on the connected property management system, and additional keys may be present; documented keys have the types shown.","examples":[{"market":"Springfield","yearBuilt":1998}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-01-05T12:00:00.000Z"]},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When this record was last updated, as an ISO 8601 timestamp. Changes to related records do not necessarily advance this value.","examples":["2026-09-20T03:15:00.000Z"]},"propertyClass":{"anyOf":[{"type":"array","items":{"type":"string","description":"One stored classification."},"description":"Stored property classifications."},{"type":"null"}],"description":"Stored property classifications.","examples":[["residential"]]},"access":{"type":"object","properties":{"gateCode":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Gate code, or null when none is recorded."},"lockboxCode":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Lockbox code, or null when none is recorded."},"alarmCode":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Alarm code, or null when none is recorded."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Access notes, or null when none is recorded."}},"required":["gateCode","lockboxCode","alarmCode","notes"],"additionalProperties":false,"description":"Access details for this property. Every key is always present. Maintained in Mason and not written to your property management system, and not yet included in vendor or technician dispatches. Lockboxes synced from your property management system are not included. Change them with PATCH /properties/{id}.","examples":[{"gateCode":"#4821","lockboxCode":null,"alarmCode":null,"notes":"Gate keypad is on the left pillar of the driveway."}]},"pauseOwnerOutreach":{"type":"boolean","description":"Whether Mason's messages to this property's owner are paused: owner approvals, dispatch and completion emails, estimate emails, and agent owner messages. Owner messages your team explicitly asks Mason to send are still sent. False when never set. Maintained in Mason and not written to your property management system; change it with PATCH /properties/{id}.","examples":[false]}},"required":["id","formattedAddress","address","address2","city","state","zip","isActive","multiUnit","ownerInfo","propertyDetails","createdAt","updatedAt","propertyClass","access","pauseOwnerOutreach"],"additionalProperties":false,"description":"Properties associated with your account, including stored address, ownership, and provider details. No geocoding or owner lookup runs as part of this read. Properties are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. This API does not create properties. PATCH /properties/{id} changes only the Mason-maintained fields access and pauseOwnerOutreach, which Mason does not write to your property management system; every other field is read-only here and changes only in your property management system."},"SchedulingBlock":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["88888888-8888-4888-8888-888888888888"]},"masonWorkOrderId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","examples":["11111111-1111-4111-8111-111111111111"]},"visitId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason visit ID; resolve using GET /visits/{id}.","examples":["77777777-7777-4777-8777-777777777777"]},"contactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","examples":["66666666-6666-4666-8666-666666666666"]},"blockType":{"type":"string","description":"Stored scheduling category, such as tenant_available, vendor_available, tentative, confirmed, tech_scheduling_proposal, blocked, superseded, on_call_assignment, on_call_override, or on_call_cancellation.","examples":["confirmed"]},"source":{"type":"string","description":"Stored scheduling source, such as tenant_portal, vendor_portal, pm_manual, or ai_suggested.","examples":["pm_manual"]},"tenantConfirmationStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored tenant confirmation status, commonly pending or confirmed; null means legacy or unknown.","examples":["pending"]},"timezone":{"type":"string","description":"IANA timezone associated with the scheduling block, for example America/Los_Angeles.","examples":["America/Chicago"]},"linkKey":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Identifier grouping blocks from one scheduling submission.","examples":["15151515-1515-4151-8151-151515151515"]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored scheduling notes.","examples":["Scheduled through the Mason API."]},"start":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}],"description":"Beginning of the stored scheduling window; null means the range is unbounded at the start.","examples":["2026-09-25T14:00:00.000Z"]},"end":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}],"description":"End of the stored scheduling window; null means the range is unbounded at the end.","examples":["2026-09-25T16:00:00.000Z"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-09-22T14:05:00.000Z"]},"expiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Expiration timestamp, when one is recorded. Expired records are not automatically excluded by this endpoint."},"createdBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored creator identifier for this block.","examples":["External API key \"Example integration\""]},"supersedesBlockId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Mason scheduling-block ID superseded by this record, when present."}},"required":["id","masonWorkOrderId","visitId","contactId","blockType","source","tenantConfirmationStatus","timezone","linkKey","notes","start","end","createdAt","expiresAt","createdBy","supersedesBlockId"],"additionalProperties":false,"description":"Stored availability and appointment blocks. blockType=confirmed identifies a confirmed work window. A confirmed block and tenantConfirmationStatus are distinct facts. Range endpoints can be null for unbounded windows."},"Unit":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["33333333-3333-4333-8333-333333333333"]},"propertyId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Owning Mason property ID; resolve using GET /properties/{id}.","examples":["22222222-2222-4222-8222-222222222222"]},"pmsUniqueId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored provider unit identifier, meaningful within the owning property/account.","examples":["unit-2b"]},"unitNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored unit label, such as A or 1B; null when none is meaningful.","examples":["2B"]},"normalizedUnitNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored normalized unit label; no normalization runs on this read.","examples":["2B"]},"unitFormattedAddress":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored formatted unit address.","examples":["123 Example St, Unit 2B, Springfield, IL 62701"]},"ownerInfo":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Owner display name."},"email":{"type":"string","description":"Owner email address."},"homePhone":{"type":"string","description":"Home phone number."},"workPhone":{"type":"string","description":"Work phone number."},"mobilePhone":{"type":"string","description":"Mobile phone number."},"otherPhone":{"type":"string","description":"Additional phone number."},"ownershipPercentage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Ownership percentage as a number (percent; 50 means fifty percent), so a stored \"50.00%\" is 50. Null when the stored value is not a number."},"isPrimary":{"type":"boolean","description":"Whether this is the primary owner."}},"additionalProperties":{},"description":"Stored property owner information. Keys vary by property management system."},"description":"Stored unit owners. Null means inherit property owners; [] explicitly means no current unit owner. This API does not materialize inherited owners."},{"type":"null"}],"description":"Stored unit owners. Null means inherit property owners; [] explicitly means no current unit owner. This API does not materialize inherited owners."},"bedrooms":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stored bedroom count.","examples":[2]},"bathrooms":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stored full bathroom count.","examples":[1]},"halfBathrooms":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stored half bathroom count.","examples":[0]},"squareFeet":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stored floor area in square feet.","examples":[850]},"rent":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stored monthly rent in integer cents.","examples":[145000]},"isOccupied":{"type":"boolean","description":"Current stored occupancy flag.","examples":[true]},"vacantSince":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"PM-local date when the current vacancy episode began; null means occupied or unknown onset."},{"type":"null"}],"description":"PM-local date when the current vacancy episode began; null means occupied or unknown onset."},"leasingReadiness":{"type":"string","enum":["unknown","not_ready","ready"],"description":"Current stored leasing readiness.","examples":["unknown"]},"inspectionDeferUntil":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"Recorded calendar date before which the unit should not be considered for another inspection."},{"type":"null"}],"description":"Recorded calendar date before which the unit should not be considered for another inspection."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-01-05T12:00:00.000Z"]},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When this record was last updated, as an ISO 8601 timestamp. Changes to related records do not necessarily advance this value.","examples":["2026-09-20T03:15:00.000Z"]},"access":{"type":"object","properties":{"gateCode":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Gate code, or null when none is recorded."},"lockboxCode":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Lockbox code, or null when none is recorded."},"alarmCode":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Alarm code, or null when none is recorded."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Access notes, or null when none is recorded."}},"required":["gateCode","lockboxCode","alarmCode","notes"],"additionalProperties":false,"description":"Access details for this unit. Every key is always present. Maintained in Mason and not written to your property management system, and not yet included in vendor or technician dispatches. Lockboxes synced from your property management system are not included. Change them with PATCH /units/{id}.","examples":[{"gateCode":null,"lockboxCode":"2468","alarmCode":null,"notes":"Lockbox is on the back door railing."}]}},"required":["id","propertyId","pmsUniqueId","unitNumber","normalizedUnitNumber","unitFormattedAddress","ownerInfo","bedrooms","bathrooms","halfBathrooms","squareFeet","rent","isOccupied","vacantSince","leasingReadiness","inspectionDeferUntil","createdAt","updatedAt","access"],"additionalProperties":false,"description":"Current stored units, authorized through their owning property. Vacancy and inspection fields do not provide complete historical cycles or a dated door-count denominator. Units are mirrored from your connected property management system, the system of record: change them there and Mason picks up the change on its next sync. This API does not create units. PATCH /units/{id} changes only the Mason-maintained access field, which Mason does not write to your property management system; every other field is read-only here and changes only in your property management system."},"Email":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["dddddddd-dddd-4ddd-8ddd-dddddddddddd"]},"messageId":{"type":"string","description":"Stored provider message ID.","examples":["msg-000000000001-example"]},"emailMessageId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored RFC Internet Message-ID header.","examples":["<owner-update-1042@mail.example.com>"]},"threadId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored provider thread or conversation ID.","examples":["thread-000000000001-example"]},"inBound":{"type":"boolean","description":"True for received email; false for sent email.","examples":[false]},"from":{"type":"string","description":"Stored sender email address.","examples":["maintenance@pm.example.com"]},"to":{"type":"array","items":{"type":"string","description":"One recipient email address."},"description":"Stored recipient addresses.","examples":[["owner@example.com"]]},"cc":{"anyOf":[{"type":"array","items":{"type":"string","description":"One CC email address."},"description":"Stored CC addresses; null when absent."},{"type":"null"}],"description":"Stored CC addresses; null when absent."},"subject":{"type":"string","description":"Stored email subject.","examples":["Work order 1042-1 at 123 Example St: work is proceeding"]},"snippet":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored preview text.","examples":["The estimate for the kitchen faucet repair was approved."]},"bodyText":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored plain-text message body.","examples":["Hello,\n\nThe estimate for the kitchen faucet repair at 123 Example St was approved and work is proceeding."]},"trimmedBody":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored bounded body; returned without further trimming.","examples":["The estimate for the kitchen faucet repair at 123 Example St was approved and work is proceeding."]},"source":{"type":"string","description":"Stored communication origin label, returned verbatim. It is attribution, not proof of delivery or a newly inferred classification.","examples":["mason"]},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded communication transport provider, returned verbatim; null means none was recorded.","examples":["gmail"]},"masonWorkOrderId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","examples":["11111111-1111-4111-8111-111111111111"]},"relatedWorkOrderIds":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Related Mason work-order ID in your account."}},{"type":"null"}],"description":"Stored related work-order IDs whose referenced work orders belong to your account. Order and duplicates are preserved; null means no array was recorded. This does not change the primary masonWorkOrderId filter."},"senderRole":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded sender role; legacy values are returned unchanged.","examples":["property_manager"]},"masonContactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","examples":["ffffffff-ffff-4fff-8fff-ffffffffffff"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-09-23T16:00:00.000Z"]},"sentAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Stored sending timestamp; null does not match a sentAfter/sentBefore bound.","examples":["2026-09-23T16:00:02.000Z"]},"receivedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Stored receiving timestamp; null does not match a receivedAfter/receivedBefore bound."},"metadata":{"anyOf":[{"type":"object","properties":{"sentByUserEmail":{"anyOf":[{"type":"string","description":"Email address of the Mason user who sent the message, only when recorded."},{"type":"null"}]}},"additionalProperties":false},{"type":"null"}],"description":"Recorded sender provenance. Only sentByUserEmail is exposed; missing keys remain absent.","examples":[{"sentByUserEmail":"manager@example.com"}]}},"required":["id","messageId","emailMessageId","threadId","inBound","from","to","cc","subject","snippet","bodyText","trimmedBody","source","provider","masonWorkOrderId","relatedWorkOrderIds","senderRole","masonContactId","createdAt","sentAt","receivedAt","metadata"],"additionalProperties":false,"description":"Stored email content and sender provenance for your account. No trimming, classification, ingestion, or sending occurs on read. Work-order filters match the primary link only."},"Estimate":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"]},"masonWorkOrderId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason work-order ID. Resolve it using GET /work-orders/{id}; null means no work order is linked.","examples":["11111111-1111-4111-8111-111111111111"]},"vendorContactId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Linked Mason contact ID. Resolve it using GET /contacts/{id}; null means no contact is linked.","examples":["55555555-5555-4555-8555-555555555555"]},"vendorName":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded vendor name.","examples":["Example Plumbing Co."]},"vendorPhone":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded vendor phone number.","examples":["+15555550188"]},"status":{"type":"string","enum":["requested","received","sent_for_approval","approved_for_work","rejected"],"description":"Stored estimate lifecycle state.","examples":["sent_for_approval"]},"estimateAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stored quoted total in integer cents.","examples":[45000]},"estimateDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored description of the quoted work.","examples":["Replace the kitchen faucet and both supply lines."]},"lineItems":{"anyOf":[{"type":"array","items":{"anyOf":[{"type":"object","properties":{"description":{"anyOf":[{"type":"string","description":"Stored line-item description."},{"type":"null"}]},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stored item quantity as a number. Null when the stored value is not a number."},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stored price per unit in cents, as a number. Null when the stored value is not a number."},"totalPrice":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stored extended price in cents, as a number. Null when the stored value is not a number."}},"additionalProperties":false},{"type":"null"}],"description":"One stored estimate line item; only the listed fields are exposed."}},{"type":"null"}],"description":"Stored estimate items, projected without recalculation; null means no valid item array was recorded.","examples":[[{"description":"Faucet","quantity":1,"unitPrice":250,"totalPrice":250},{"description":"Labor","quantity":2,"unitPrice":100,"totalPrice":200}]]},"estimateNotes":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored business notes accompanying the estimate."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored estimate source, such as vendor_sms, vendor_call, vendor_email, pm_inbox_email, manual, or appfolio.","examples":["vendor_email"]},"sourceMessageId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Stored source message record ID, when available."},"sourceCallId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}],"description":"Stored source Mason call ID, when available."},"approvedByRole":{"anyOf":[{"type":"string","enum":["pm","owner"],"description":"Role recorded as approving the estimate; null means none recorded."},{"type":"null"}],"description":"Role recorded as approving the estimate; null means none recorded."},"approvedAmount":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Stored approved amount in integer cents; may differ from the quote."},"approvedScope":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored approved work scope; may differ from the quote."},"pmApprovedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Recorded approval timestamp; may represent a PM or owner decision."},"pmApprovedBy":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Recorded approver identifier, typically an email; may identify a PM or owner."},"pmRejectedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"ISO 8601 timestamp."},{"type":"null"}],"description":"Recorded rejection timestamp; may represent a PM or owner decision."},"pmRejectionReason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Stored business reason for rejection."},"ownerMessageDrafted":{"type":"boolean","description":"Whether an owner message was drafted; this is not evidence that it was sent or delivered.","examples":[false]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When the record was created in Mason, as an ISO 8601 timestamp.","examples":["2026-09-22T19:00:00.000Z"]},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When this record was last updated, as an ISO 8601 timestamp. Changes to related records do not necessarily advance this value.","examples":["2026-09-22T19:30:00.000Z"]}},"required":["id","masonWorkOrderId","vendorContactId","vendorName","vendorPhone","status","estimateAmount","estimateDescription","lineItems","estimateNotes","source","sourceMessageId","sourceCallId","approvedByRole","approvedAmount","approvedScope","pmApprovedAt","pmApprovedBy","pmRejectedAt","pmRejectionReason","ownerMessageDrafted","createdAt","updatedAt"],"additionalProperties":false,"description":"Stored vendor estimates and recorded approval decisions. Money is cents. Legacy PM-prefixed decision fields can represent owner decisions; ownerMessageDrafted does not prove delivery."},"WorkOrderActivity":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Unique Mason record ID. Use this value in the corresponding detail endpoint.","examples":["eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"]},"masonWorkOrderId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Owning Mason work-order ID. Always present; resolve using GET /work-orders/{id}.","examples":["11111111-1111-4111-8111-111111111111"]},"eventType":{"type":"string","enum":["status_changed","work_order_pm_assignee_added","work_order_pm_assignee_replaced","tenant_confirmed_scheduling","tenant_confirmation_status_updated","tenant_canceled_scheduling","pms_schedule_reconciled","schedule_change_reviewed","emergency_escalation_started","emergency_escalation_acknowledged","emergency_escalation_cancelled","invoice_approved","invoice_rejected","invoice_unapproved","invoice_rejection_undone","vendor_invoice_submitted","tenant_work_completed","owner_work_completed","vendor_work_completed","vendor_work_completion_undone","visit_rescheduled","visit_unscheduled","portal_visit_unscheduled","visit_reassigned","vendor_scheduled_time_confirmed","vendor_work_order_confirmed","pms_vendor_accepted","vendor_reject_work","tech_accepted_job","tech_denied_job","estimate_requested","estimate_sent_for_owner_approval","estimate_approved","estimate_rejected"],"description":"Allowlisted stored business event type; determines the details structure.","examples":["status_changed"]},"timestamp":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Stored event occurrence timestamp. after/before are inclusive bounds on this field.","examples":["2026-09-23T16:00:00.000Z"]},"source":{"type":"string","description":"Stored event origin label, returned unchanged. No execution payload or trace accompanies it.","examples":["external_api"]},"details":{"anyOf":[{"type":"object","properties":{"from":{"type":"string","description":"Stored previous work-order status."},"to":{"type":"string","description":"Stored new work-order status."},"userEmail":{"anyOf":[{"type":"string","description":"Recorded acting user email, when available."},{"type":"null"}]},"note":{"anyOf":[{"type":"string","description":"Business status note recorded under a Mason UI or external API source."},{"type":"null"}]},"reason":{"type":"string","const":"deleted_in_appfolio","description":"Recorded AppFolio deletion reason, exposed only for appfolio_sync events."}},"required":["from","to"],"additionalProperties":false,"description":"Selected stored details for status_changed; absent optional keys are not synthesized."},{"type":"object","properties":{"assigneeContactId":{"type":"string","description":"Recorded Mason PM assignee contact ID."}},"required":["assigneeContactId"],"additionalProperties":false,"description":"Selected stored details for work_order_pm_assignee_added; absent optional keys are not synthesized."},{"type":"object","properties":{"assigneeContactId":{"type":"string","description":"Recorded replacement Mason PM assignee contact ID."},"replacedAssigneeContactId":{"type":"string","description":"Recorded previous Mason PM assignee contact ID."}},"required":["assigneeContactId","replacedAssigneeContactId"],"additionalProperties":false,"description":"Selected stored details for work_order_pm_assignee_replaced; absent optional keys are not synthesized."},{"type":"object","properties":{"schedulingBlockId":{"type":"string","description":"Mason scheduling-block ID recorded by this event."},"priorStatus":{"anyOf":[{"type":"string","description":"Tenant confirmation status recorded before this change."},{"type":"null"}]},"confirmedAt":{"type":"string","description":"Recorded tenant confirmation timestamp."}},"required":["schedulingBlockId","confirmedAt"],"additionalProperties":false,"description":"Selected stored details for tenant_confirmed_scheduling; absent optional keys are not synthesized."},{"type":"object","properties":{"schedulingBlockId":{"type":"string","description":"Mason scheduling-block ID recorded by this event."},"priorStatus":{"anyOf":[{"type":"string","description":"Tenant confirmation status recorded before this change."},{"type":"null"}]},"tenantConfirmationStatus":{"type":"string","description":"Stored new tenant confirmation status."},"updatedBy":{"anyOf":[{"type":"string","description":"Recorded dispatcher email."},{"type":"null"}]},"updatedAt":{"type":"string","description":"Recorded confirmation update timestamp."},"userEmail":{"anyOf":[{"type":"string","description":"Recorded acting user email."},{"type":"null"}]}},"required":["schedulingBlockId","tenantConfirmationStatus","updatedAt"],"additionalProperties":false,"description":"Selected stored details for tenant_confirmation_status_updated; absent optional keys are not synthesized."},{"type":"object","properties":{"canceledAt":{"type":"string","description":"Recorded cancellation timestamp."},"blocksAffected":{"anyOf":[{"type":"number","description":"Number of scheduling blocks recorded as affected."},{"type":"null"}]}},"required":["canceledAt"],"additionalProperties":false,"description":"Selected stored details for tenant_canceled_scheduling; absent optional keys are not synthesized."},{"type":"object","properties":{"externalRecordId":{"type":"string","description":"Provider work-order record ID."},"externalOccurrenceId":{"anyOf":[{"type":"string","description":"Provider appointment occurrence ID, when recorded."},{"type":"null"}]},"reconciledAt":{"type":"string","description":"Recorded schedule reconciliation timestamp."},"desired":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","description":"Stored appointment status: scheduled, unscheduled, cancelled, or completed."},"startIso":{"anyOf":[{"type":"string","description":"Stored appointment start timestamp."},{"type":"null"}]},"endIso":{"anyOf":[{"type":"string","description":"Stored appointment end timestamp."},{"type":"null"}]},"assigneeExternalIds":{"anyOf":[{"type":"array","items":{"type":"string","description":"One recorded identifier."},"description":"Recorded provider assignee IDs."},{"type":"null"}]},"assigneeIds":{"anyOf":[{"type":"array","items":{"type":"string","description":"One recorded identifier."},"description":"Recorded Mason assignee contact IDs."},{"type":"null"}]},"assigneeId":{"anyOf":[{"type":"string","description":"Recorded primary assignee ID."},{"type":"null"}]}},"required":["status"],"additionalProperties":false},{"type":"null"}],"description":"Recorded reconciled appointment facts. Null is preserved; no current state is inferred."}},"required":["externalRecordId","reconciledAt","desired"],"additionalProperties":false,"description":"Selected stored details for pms_schedule_reconciled; absent optional keys are not synthesized."},{"type":"object","properties":{"decision":{"type":"string","description":"Stored communication decision: notified or no_message. This record alone does not prove recipient delivery."},"reviewedAt":{"type":"string","description":"Recorded schedule review timestamp."}},"required":["decision","reviewedAt"],"additionalProperties":false,"description":"Selected stored details for schedule_change_reviewed; absent optional keys are not synthesized."},{"type":"object","properties":{"dispatchTime":{"anyOf":[{"type":"string","description":"Recorded dispatch urgency label, such as ASAP or NEXT_DAY; not a timestamp."},{"type":"null"}]},"emergencyType":{"anyOf":[{"type":"string","description":"Recorded emergency category."},{"type":"null"}]},"firstContact":{"anyOf":[{"type":"string","description":"Recorded first contact names; does not prove they were reached."},{"type":"null"}]},"escalationType":{"anyOf":[{"type":"string","description":"Recorded escalation contact selection type."},{"type":"null"}]},"sourceMasonCallId":{"anyOf":[{"type":"string","description":"Mason call ID associated with the escalation."},{"type":"null"}]}},"additionalProperties":false,"description":"Selected stored details for emergency_escalation_started; absent optional keys are not synthesized."},{"type":"object","properties":{"acknowledgedBy":{"anyOf":[{"type":"string","description":"Recorded acknowledgement channel or mechanism; not necessarily a person."},{"type":"null"}]},"contactName":{"anyOf":[{"type":"string","description":"Recorded acknowledging contact name."},{"type":"null"}]},"vendorContactId":{"anyOf":[{"type":"string","description":"Recorded accepting Mason vendor contact ID."},{"type":"null"}]},"vendorName":{"anyOf":[{"type":"string","description":"Recorded accepting vendor name."},{"type":"null"}]},"escalationResolutionWon":{"anyOf":[{"type":"boolean","description":"Whether this auto-dispatch acceptance resolved the escalation."},{"type":"null"}]},"onCallEscalationContinued":{"anyOf":[{"type":"boolean","description":"Whether on-call escalation continued after auto-dispatch acceptance."},{"type":"null"}]}},"additionalProperties":false,"description":"Selected stored details for emergency_escalation_acknowledged; absent optional keys are not synthesized."},{"type":"object","properties":{"acknowledgedBy":{"type":"string","description":"Recorded cancellation channel or mechanism."},"contactName":{"anyOf":[{"type":"string","description":"Recorded contact name associated with cancellation."},{"type":"null"}]},"standDownReason":{"anyOf":[{"type":"string","description":"Recorded category explaining why the escalation stopped."},{"type":"null"}]}},"required":["acknowledgedBy"],"additionalProperties":false,"description":"Selected stored details for emergency_escalation_cancelled; absent optional keys are not synthesized."},{"type":"object","properties":{"invoiceId":{"type":"string","description":"Mason invoice ID associated with this event."},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]},"amount":{"anyOf":[{"type":"number","description":"Recorded invoice amount in integer cents; null means no amount was recorded."},{"type":"null"}]},"currency":{"anyOf":[{"type":"string","description":"Recorded invoice currency code."},{"type":"null"}]},"approvedBy":{"anyOf":[{"type":"string","description":"Recorded invoice approver identifier."},{"type":"null"}]}},"required":["invoiceId"],"additionalProperties":false,"description":"Selected stored details for invoice_approved; absent optional keys are not synthesized."},{"type":"object","properties":{"invoiceId":{"type":"string","description":"Mason invoice ID associated with this event."},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]},"amount":{"anyOf":[{"type":"number","description":"Recorded invoice amount in integer cents; null means no amount was recorded."},{"type":"null"}]},"currency":{"anyOf":[{"type":"string","description":"Recorded invoice currency code."},{"type":"null"}]},"rejectedBy":{"anyOf":[{"type":"string","description":"Recorded invoice rejector identifier."},{"type":"null"}]}},"required":["invoiceId"],"additionalProperties":false,"description":"Selected stored details for invoice_rejected; absent optional keys are not synthesized."},{"type":"object","properties":{"invoiceId":{"type":"string","description":"Mason invoice ID associated with this event."},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]},"amount":{"anyOf":[{"type":"number","description":"Recorded invoice amount in integer cents; null means no amount was recorded."},{"type":"null"}]},"currency":{"anyOf":[{"type":"string","description":"Recorded invoice currency code."},{"type":"null"}]},"unapprovedBy":{"anyOf":[{"type":"string","description":"Recorded user who undid invoice approval."},{"type":"null"}]}},"required":["invoiceId"],"additionalProperties":false,"description":"Selected stored details for invoice_unapproved; absent optional keys are not synthesized."},{"type":"object","properties":{"invoiceId":{"type":"string","description":"Mason invoice ID associated with this event."},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]},"amount":{"anyOf":[{"type":"number","description":"Recorded invoice amount in integer cents; null means no amount was recorded."},{"type":"null"}]},"currency":{"anyOf":[{"type":"string","description":"Recorded invoice currency code."},{"type":"null"}]},"unrejectedBy":{"anyOf":[{"type":"string","description":"Recorded user who undid invoice rejection."},{"type":"null"}]}},"required":["invoiceId"],"additionalProperties":false,"description":"Selected stored details for invoice_rejection_undone; absent optional keys are not synthesized."},{"type":"object","properties":{"vendorContactId":{"anyOf":[{"type":"string","description":"Recorded Mason vendor contact ID."},{"type":"null"}]},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]},"amountDue":{"anyOf":[{"type":"string","description":"Stored decimal dollar amount as text, not integer cents; null means no amount was entered."},{"type":"null"}]},"serviceDate":{"anyOf":[{"type":"string","description":"Recorded service date."},{"type":"null"}]},"submittedAt":{"type":"string","description":"Recorded invoice submission timestamp."},"completionOutcome":{"anyOf":[{"type":"string","description":"Recorded visit outcome; submitting an invoice does not necessarily complete the repair."},{"type":"null"}]}},"required":["submittedAt"],"additionalProperties":false,"description":"Selected stored details for vendor_invoice_submitted; absent optional keys are not synthesized."},{"type":"object","properties":{"completionReason":{"type":"string","description":"Recorded completion category, not a new assessment of the work."},"markedCompleteAt":{"type":"string","description":"Recorded completion timestamp."},"markedBy":{"anyOf":[{"type":"string","description":"Recorded role reporting completion, when present."},{"type":"null"}]},"vendorContactId":{"anyOf":[{"type":"string","description":"Recorded Mason vendor contact ID."},{"type":"null"}]},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]}},"required":["completionReason","markedCompleteAt"],"additionalProperties":false,"description":"Selected stored details for tenant_work_completed; absent optional keys are not synthesized."},{"type":"object","properties":{"completionReason":{"type":"string","description":"Recorded completion category, not a new assessment of the work."},"markedCompleteAt":{"type":"string","description":"Recorded completion timestamp."},"markedBy":{"anyOf":[{"type":"string","description":"Recorded role reporting completion, when present."},{"type":"null"}]},"vendorContactId":{"anyOf":[{"type":"string","description":"Recorded Mason vendor contact ID."},{"type":"null"}]},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]}},"required":["completionReason","markedCompleteAt"],"additionalProperties":false,"description":"Selected stored details for owner_work_completed; absent optional keys are not synthesized."},{"type":"object","properties":{"vendorContactId":{"anyOf":[{"type":"string","description":"Recorded Mason vendor contact ID."},{"type":"null"}]},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]},"markedCompleteAt":{"type":"string","description":"Recorded vendor completion timestamp."}},"required":["markedCompleteAt"],"additionalProperties":false,"description":"Selected stored details for vendor_work_completed; absent optional keys are not synthesized."},{"type":"object","properties":{"vendorContactId":{"anyOf":[{"type":"string","description":"Recorded Mason vendor contact ID."},{"type":"null"}]},"vendorName":{"anyOf":[{"type":"string","description":"Recorded vendor name."},{"type":"null"}]},"undoneAt":{"type":"string","description":"Recorded timestamp when vendor completion was undone."}},"required":["undoneAt"],"additionalProperties":false,"description":"Selected stored details for vendor_work_completion_undone; absent optional keys are not synthesized."},{"type":"object","properties":{"requestedBy":{"type":"string","description":"Recorded role requesting the reschedule."},"techContactId":{"type":"string","description":"Recorded Mason technician contact ID."},"previousBlockId":{"type":"string","description":"Scheduling-block ID before the reschedule."},"tenantAvailabilityBlockId":{"anyOf":[{"type":"string","description":"Recorded tenant availability scheduling-block ID."},{"type":"null"}]},"timeRange":{"type":"string","description":"Stored replacement appointment window in PostgreSQL timestamp-range notation."},"assignmentSuccess":{"type":"boolean","description":"Recorded result of assigning the replacement appointment."}},"required":["requestedBy","techContactId","previousBlockId","timeRange","assignmentSuccess"],"additionalProperties":false,"description":"Selected stored details for visit_rescheduled; absent optional keys are not synthesized."},{"type":"object","properties":{"blockIds":{"type":"array","items":{"type":"string","description":"One recorded identifier."},"description":"Recorded scheduling-block IDs that were cancelled."},"blocksAffected":{"type":"number","description":"Recorded number of cancelled scheduling blocks."},"unscheduledAt":{"type":"string","description":"Recorded unscheduling timestamp."},"actorRole":{"anyOf":[{"type":"string","description":"Recorded role that requested the change."},{"type":"null"}]},"actorName":{"anyOf":[{"type":"string","description":"Recorded name of the actor."},{"type":"null"}]},"visitId":{"anyOf":[{"type":"string","description":"Mason visit ID, when recorded."},{"type":"null"}]}},"required":["blockIds","blocksAffected","unscheduledAt"],"additionalProperties":false,"description":"Selected stored details for visit_unscheduled; absent optional keys are not synthesized."},{"type":"object","properties":{"blockIds":{"type":"array","items":{"type":"string","description":"One recorded identifier."},"description":"Recorded scheduling-block IDs that were cancelled."},"blocksAffected":{"type":"number","description":"Recorded number of cancelled scheduling blocks."},"unscheduledAt":{"type":"string","description":"Recorded unscheduling timestamp."},"actorRole":{"anyOf":[{"type":"string","description":"Recorded role that requested the change."},{"type":"null"}]},"actorName":{"anyOf":[{"type":"string","description":"Recorded name of the actor."},{"type":"null"}]},"visitId":{"anyOf":[{"type":"string","description":"Mason visit ID, when recorded."},{"type":"null"}]}},"required":["blockIds","blocksAffected","unscheduledAt"],"additionalProperties":false,"description":"Selected stored details for portal_visit_unscheduled; absent optional keys are not synthesized."},{"type":"object","properties":{"previousAssigneeContactId":{"type":"string","description":"Previous Mason technician contact ID."},"assigneeContactId":{"type":"string","description":"Replacement Mason technician contact ID."},"userEmail":{"anyOf":[{"type":"string","description":"Recorded user requesting the reassignment."},{"type":"null"}]},"visitId":{"type":"string","description":"Mason visit ID whose technician changed."}},"required":["previousAssigneeContactId","assigneeContactId","visitId"],"additionalProperties":false,"description":"Selected stored details for visit_reassigned; absent optional keys are not synthesized."},{"type":"object","properties":{"scheduledDate":{"type":"string","description":"Recorded appointment date."},"scheduledTime":{"anyOf":[{"type":"string","description":"Recorded appointment time or arrival-window text."},{"type":"null"}]},"confirmedAt":{"type":"string","description":"Recorded scheduling confirmation timestamp."},"vendorName":{"anyOf":[{"type":"string","description":"Recorded scheduling party name."},{"type":"null"}]}},"required":["scheduledDate","confirmedAt"],"additionalProperties":false,"description":"Selected stored details for vendor_scheduled_time_confirmed; absent optional keys are not synthesized."},{"type":"object","properties":{"vendorContactId":{"anyOf":[{"type":"string","description":"Recorded accepting Mason vendor contact ID."},{"type":"null"}]},"vendorName":{"anyOf":[{"type":"string","description":"Recorded accepting vendor name."},{"type":"null"}]},"confirmedAt":{"type":"string","description":"Recorded vendor acceptance timestamp."},"observedAt":{"anyOf":[{"type":"string","description":"When Mason observed the acceptance."},{"type":"null"}]},"timestampSource":{"anyOf":[{"type":"string","description":"Recorded origin of the acceptance timestamp."},{"type":"null"}]}},"required":["confirmedAt"],"additionalProperties":false,"description":"Selected stored details for vendor_work_order_confirmed; absent optional keys are not synthesized."},{"type":"object","properties":{"vendorContactId":{"anyOf":[{"type":"string","description":"Recorded accepting Mason vendor contact ID."},{"type":"null"}]},"vendorName":{"anyOf":[{"type":"string","description":"Recorded accepting vendor name."},{"type":"null"}]},"eventTimestamp":{"anyOf":[{"type":"string","description":"Provider occurrence timestamp, when known."},{"type":"null"}]},"observedAt":{"type":"string","description":"When Mason observed the provider acceptance. This event may overlap vendor_work_order_confirmed and must not be counted as a separate acceptance."},"timestampSource":{"anyOf":[{"type":"string","description":"Recorded origin of the acceptance timestamp."},{"type":"null"}]},"timestampPrecision":{"anyOf":[{"type":"string","description":"Recorded precision of the acceptance timestamp."},{"type":"null"}]}},"required":["observedAt"],"additionalProperties":false,"description":"Selected stored details for pms_vendor_accepted; absent optional keys are not synthesized."},{"type":"object","properties":{"vendorName":{"anyOf":[{"type":"string","description":"Recorded declining vendor name."},{"type":"null"}]},"rejectingVendorId":{"anyOf":[{"type":"string","description":"Recorded declining Mason vendor contact ID, when present."},{"type":"null"}]},"rejectedAt":{"type":"string","description":"Recorded vendor rejection timestamp; does not imply the work-order assignment changed."}},"required":["rejectedAt"],"additionalProperties":false,"description":"Selected stored details for vendor_reject_work; absent optional keys are not synthesized."},{"type":"object","properties":{"techName":{"anyOf":[{"type":"string","description":"Recorded accepting technician name."},{"type":"null"}]},"confirmedAt":{"type":"string","description":"Recorded technician acceptance timestamp."},"visitId":{"type":"string","description":"Mason visit ID accepted by the technician."}},"required":["confirmedAt","visitId"],"additionalProperties":false,"description":"Selected stored details for tech_accepted_job; absent optional keys are not synthesized."},{"type":"object","properties":{"techName":{"anyOf":[{"type":"string","description":"Recorded declining technician name."},{"type":"null"}]},"deniedAt":{"type":"string","description":"Recorded technician rejection timestamp."},"visitId":{"type":"string","description":"Mason visit ID declined by the technician."}},"required":["deniedAt","visitId"],"additionalProperties":false,"description":"Selected stored details for tech_denied_job; absent optional keys are not synthesized."},{"type":"object","properties":{"estimateId":{"type":"string","description":"Mason estimate ID associated with this recorded event."}},"required":["estimateId"],"additionalProperties":false,"description":"Selected stored details for estimate_requested; absent optional keys are not synthesized."},{"type":"object","properties":{"estimateId":{"type":"string","description":"Mason estimate ID associated with this recorded event."},"ownerEmail":{"anyOf":[{"type":"string","description":"Owner email recorded on the approval request."},{"type":"null"}]},"emailSent":{"anyOf":[{"type":"boolean","description":"Stored sending result, only when the writer recorded it."},{"type":"null"}]},"emailRecordId":{"anyOf":[{"type":"string","description":"Mason email record ID, only when recorded."},{"type":"null"}]}},"required":["estimateId"],"additionalProperties":false,"description":"Selected stored details for estimate_sent_for_owner_approval; absent optional keys are not synthesized."},{"type":"object","properties":{"estimateId":{"type":"string","description":"Mason estimate ID associated with this recorded event."},"approvedBy":{"anyOf":[{"type":"string","description":"Recorded approver identifier, typically an email address."},{"type":"null"}]},"actorRole":{"anyOf":[{"type":"string","description":"Recorded role that requested the change."},{"type":"null"}]},"actorName":{"anyOf":[{"type":"string","description":"Recorded name of the actor."},{"type":"null"}]}},"required":["estimateId"],"additionalProperties":false,"description":"Selected stored details for estimate_approved; absent optional keys are not synthesized."},{"type":"object","properties":{"estimateId":{"type":"string","description":"Mason estimate ID associated with this recorded event."},"rejectedBy":{"anyOf":[{"type":"string","description":"Recorded rejecting person identifier, typically an email address."},{"type":"null"}]},"actorRole":{"anyOf":[{"type":"string","description":"Recorded role that requested the change."},{"type":"null"}]},"actorName":{"anyOf":[{"type":"string","description":"Recorded name of the actor."},{"type":"null"}]}},"required":["estimateId"],"additionalProperties":false,"description":"Selected stored details for estimate_rejected; absent optional keys are not synthesized."}],"description":"Event-specific business fields only. Interpret this structure with eventType. Unrecognized payload versions and malformed selected fields are excluded from list and detail reads. History can be incomplete.","examples":[{"from":"reviewed","to":"work_in_progress","note":"Vendor confirmed the repair."}]}},"required":["id","masonWorkOrderId","eventType","timestamp","source","details"],"additionalProperties":false,"description":"Allowlisted stored business events, authorized through the owning work order. Unsupported event types/versions and malformed selected payloads are excluded before pagination and from detail reads. No complete-history guarantee; absence is not proof an action never occurred. Sorts by timestamp and ID descending."},"CreateWorkOrderRequest":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":5000,"description":"Problem description as the requester reported it."},"propertyId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason property UUID from the properties in this account."},"unitId":{"description":"Mason unit UUID. Must belong to propertyId. Defaults to the tenant's leased unit when tenantContactId is given.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"tenantContactId":{"description":"Mason contact UUID of the tenant reporting the issue. Must lease within propertyId (and unitId when given).","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"workOrderType":{"description":"Canonical work-order type. When omitted, Mason's review classifies the work order.","type":"string","enum":["reactive","reactive:recall","preventative","turn","recurring","misc","inspection","inspection:move_in","inspection:move_out","inspection:pre_move_out","inspection:onboarding","inspection:semi_annual","inspection:drive_by","inspection:annual"]},"source":{"description":"How the request reached you. mason:portal (default) records the property manager as requester; mason:call and mason:text record the tenant; pms:portal records a request first entered in the property management system.","type":"string","enum":["mason:portal","mason:call","mason:text","pms:portal"]}},"required":["description","propertyId"],"additionalProperties":false,"description":"Work order to create."},"UpdateWorkOrderRequest":{"type":"object","properties":{"description":{"description":"Replacement description. Also synchronized to the property management system.","type":"string","minLength":1,"maxLength":5000},"status":{"description":"New lifecycle status. Applied last, after the other fields in the request. Starts the same follow-up workflows as a status change in Mason and is synchronized to the property management system.","type":"string","enum":["created","reviewed","estimated","work_in_progress","duplicate","cancelled","not_handled_by_mason","work_done","closed"]},"statusNote":{"description":"Note recorded with the status change. Requires status.","type":"string","minLength":1,"maxLength":2000},"priority":{"description":"Attention priority override. null clears the override and returns to Mason's assessed priority.","anyOf":[{"type":"string","enum":["urgent","normal","low"]},{"type":"null"}]},"workOrderType":{"type":"string","enum":["reactive","reactive:recall","preventative","turn","recurring","misc","inspection","inspection:move_in","inspection:move_out","inspection:pre_move_out","inspection:onboarding","inspection:semi_annual","inspection:drive_by","inspection:annual"],"description":"Canonical work-order type. Subtypes such as inspection:move_in are distinct values."},"isEmergency":{"description":"Emergency flag. false cancels any open emergency escalation for this work order.","type":"boolean"},"assignment":{"anyOf":[{"type":"object","properties":{"vendorContactId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason contact UUID of a contact with contactType vendor in this account. Resolve contacts using GET /contacts."}},"required":["vendorContactId"],"additionalProperties":false,"description":"Dispatch to a third-party vendor."},{"type":"object","properties":{"technicianContactId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason contact UUID of a contact with contactType tech in this account. Resolve contacts using GET /contacts."}},"required":["technicianContactId"],"additionalProperties":false,"description":"Assign an in-house technician."}],"description":"Vendor or in-house technician to assign, through the same dispatch path as a manual dispatch from the Mason app, with the differences listed on PATCH /work-orders/{id}. Mason uses the dispatch form's defaults: the work order's current scope as instructions, an estimate request when Mason's review recommends one, the property's synced gate and lockbox codes, the vendor's preferred dispatch channel when it can be reached that way (otherwise email, or a text message when the vendor has no email), and a target completion date three business days out. No not-to-exceed amount is sent; the property's maintenance limit applies where one is configured. A vendor assignment starts Mason's vendor outreach and follow-up and sends no tenant or owner notification. A technician assignment creates and sends the technician's visit ticket and sends no owner notification; when the account has tenant scheduling enabled, the tenant is texted a link to schedule the visit. A previously dispatched vendor is sent a cancellation. The assigned contact is then returned in the work-order vendorContactId field. The assignment is synchronized to the property management system: if it rejects a vendor assignment, nothing is sent and the request returns 502; if it rejects a technician assignment, the Mason assignment stands and the response reports pmsAssignmentError. Assigning a vendor already assigned or dispatched on this work order, or a technician already assigned to it, returns 409."}},"additionalProperties":false,"description":"Fields to change. Omitted fields are left unchanged. Fields are applied in the order workOrderType, description, priority, isEmergency, assignment, status; the request stops at the first failure."},"WorkOrderUpdateError":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message for people. It can change; branch on code instead. No diagnostic stack or execution details are returned."},"code":{"type":"string","enum":["unauthorized","token_expired","insufficient_scope","account_not_live","unknown_resource","not_found","method_not_allowed","invalid_parameter","invalid_body","idempotency_key_required","idempotency_in_progress","idempotency_request_unfinished","idempotency_key_reused","precondition_failed","conflict","rate_limited","pms_write_failed","dispatch_failed","calendar_unavailable","internal_error"],"description":"Stable machine-readable error code. A code keeps its meaning once published; new codes may be added, so handle an unrecognized code by its HTTP status. Codes:\n\n- unauthorized: The Authorization header is missing or malformed, or the bearer token is unknown or revoked.\n- token_expired: The bearer token has expired. Create a new API key.\n- insufficient_scope: The API key is read-only and the request needs a read & write key.\n- account_not_live: Work-order creation becomes available once the account is live in Mason.\n- unknown_resource: The path does not name a supported resource or endpoint.\n- not_found: No record with that ID exists in this account, or the ID is not a valid UUID.\n- method_not_allowed: The resource does not support this HTTP method.\n- invalid_parameter: A query parameter is unknown or has an invalid value; the message names it.\n- invalid_body: The request body is not valid JSON, has unknown fields, or a field value was rejected; the message explains which.\n- idempotency_key_required: The write requires an Idempotency-Key header: 1-255 printable ASCII characters, unique per write.\n- idempotency_in_progress: Another request with this Idempotency-Key is still being processed. Retry later with the same key.\n- idempotency_request_unfinished: An earlier request with this Idempotency-Key did not finish. Check whether it took effect before retrying with a new key.\n- idempotency_key_reused: This Idempotency-Key was already used with a different request.\n- precondition_failed: If-Match did not match the current ETag. Nothing was applied; read the record again.\n- conflict: The change conflicts with the record's current state; the message explains the conflict.\n- rate_limited: Too many requests for this account. Retry after the Retry-After header.\n- pms_write_failed: A write to the property management system, or the Mason update that follows it, failed; the message says which.\n- dispatch_failed: The vendor or technician dispatch could not be completed; the message explains why.\n- calendar_unavailable: The technician's connected calendar could not be checked. Nothing was changed; retry shortly.\n- internal_error: The request could not be completed. For a write, the message says whether it may have partially taken effect."},"requestId":{"type":"string","description":"Identifier of this request, the same value as the X-Mason-Request-Id response header. Quote it when contacting Mason support. A replayed idempotent response carries the ID of the replaying request."},"field":{"type":"string","enum":["workOrderType","description","priority","isEmergency","assignment","status"],"description":"The field whose change failed."},"appliedFields":{"type":"array","items":{"type":"string","enum":["workOrderType","description","priority","isEmergency","assignment","status"]},"description":"Fields from this request already applied before the failure. They are not rolled back."},"pmsAssignmentError":{"type":"string","description":"Present only when a technician assignment in this request was applied in Mason but the property management system rejected it. The Mason assignment stands; update the property management system yourself."}},"required":["error","code","requestId","field","appliedFields"],"additionalProperties":false,"description":"A work-order update that stopped at a failing field, with the standard error fields."},"UpdateEstimateRequest":{"oneOf":[{"type":"object","properties":{"status":{"type":"string","const":"approved","description":"Approve the estimate. The record then reads status approved_for_work."},"approvedAmount":{"description":"Approved amount in integer cents, when you approve less than the vendor's quote. Defaults to the estimate amount.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"approvedScope":{"description":"Approved scope, when you approve only part of the quoted work. Omitted means the full quoted scope.","type":"string","minLength":1,"maxLength":5000},"approvedByRole":{"description":"Who approved the work: pm (default) when the property manager approves, or owner to record the property owner's approval, for example one collected in your owner portal. Stored as the estimate's approvedByRole. With owner, Mason does not email the owner that work is proceeding. On an estimate that is already approved, a value different from its recorded approvedByRole returns 409.","type":"string","enum":["pm","owner"]},"skipReschedule":{"description":"true skips the follow-up visit reset: the work order's confirmed appointments are kept and the tenant is not sent a new scheduling link. Defaults to false.","type":"boolean"}},"required":["status"],"additionalProperties":false,"description":"Estimate approval."},{"type":"object","properties":{"status":{"type":"string","const":"rejected","description":"Reject the estimate. The record then reads status rejected."},"reason":{"description":"Why the estimate is rejected. Recorded on the estimate and given to the Mason agent that notifies the vendor, which shares it only when it is appropriate for the vendor to read.","type":"string","minLength":1,"maxLength":1000},"rejectedByRole":{"description":"Who rejected the estimate: pm (default) when the property manager rejects, or owner to record the property owner's decision, for example one collected in your owner portal. Recorded as the actor role on the work order's estimate_rejected activity event (GET /work-order-activity-logs, details.actorRole); the estimate record itself has no rejection role. On an estimate that is already rejected the request returns 200 without changes.","type":"string","enum":["pm","owner"]}},"required":["status"],"additionalProperties":false,"description":"Estimate rejection."}],"description":"Estimate decision, selected by status. approvedAmount, approvedScope, approvedByRole, and skipReschedule are accepted only with approved; reason and rejectedByRole only with rejected."},"UpdateInvoiceRequest":{"oneOf":[{"type":"object","properties":{"decision":{"type":"string","const":"approved","description":"Approve the invoice to pay. The record then reads pmApproved true."},"confirmMissingInvoiceNumber":{"description":"true confirms the invoice has no invoice number. Without it, approving an invoice with no number returns 400.","type":"boolean"},"confirmInactiveProperty":{"description":"true confirms approval although the invoice's property is inactive in your property management system. Without it, that approval returns 409.","type":"boolean"}},"required":["decision"],"additionalProperties":false,"description":"Invoice approval."},{"type":"object","properties":{"decision":{"type":"string","const":"rejected","description":"Reject the invoice. The record then reads pmRejected true."},"reason":{"description":"Why the invoice is rejected. Recorded on the invoice and sent with the decline to a linked property management system invoice.","type":"string","minLength":1,"maxLength":1000}},"required":["decision"],"additionalProperties":false,"description":"Invoice rejection."}],"description":"Invoice decision, selected by decision. The invoice's status field is its processing state and does not change. confirmMissingInvoiceNumber and confirmInactiveProperty are accepted only with approved; reason only with rejected."},"CreateSchedulingBlockRequest":{"type":"object","properties":{"visitId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason visit UUID to schedule. Resolve it using GET /visits?masonWorkOrderId=. Assigning a technician with PATCH /work-orders/{id} creates the visit."},"technicianContactId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Mason contact UUID of an active technician (contactType tech) in this account. Resolve contacts using GET /contacts."},"start":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Appointment start. Must be in the future. ISO 8601 timestamp with Z or a UTC offset, in whole minutes. Mason converts it to the visit's scheduling timezone; start and end must fall on the same calendar day there."},"end":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Appointment end. Must be after start. ISO 8601 timestamp with Z or a UTC offset, in whole minutes. Mason converts it to the visit's scheduling timezone; start and end must fall on the same calendar day there."},"notes":{"description":"Note recorded with the change in the work-order activity log. When the request books or moves an appointment, it is also stored as the new appointment's notes. Mason records a default note when omitted.","type":"string","minLength":1,"maxLength":1000}},"required":["visitId","technicianContactId","start","end"],"additionalProperties":false,"description":"Confirmed appointment to book for an in-house visit."},"UpdateSchedulingBlockRequest":{"anyOf":[{"type":"object","properties":{"start":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Replacement appointment start. Requires end. ISO 8601 timestamp with Z or a UTC offset, in whole minutes. Mason converts it to the visit's scheduling timezone; start and end must fall on the same calendar day there."},"end":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"Replacement appointment end. Requires start. ISO 8601 timestamp with Z or a UTC offset, in whole minutes. Mason converts it to the visit's scheduling timezone; start and end must fall on the same calendar day there."},"technicianContactId":{"description":"Technician to move the appointment to. Mason contact UUID of an active technician (contactType tech) in this account.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"notes":{"description":"Note recorded with the change in the work-order activity log. When the request books or moves an appointment, it is also stored as the new appointment's notes. Mason records a default note when omitted.","type":"string","minLength":1,"maxLength":1000}},"additionalProperties":false,"description":"Move or reassign. Send start and end to move the appointment (optionally with technicianContactId), or technicianContactId alone to reassign it at the same time."},{"type":"object","properties":{"blockType":{"type":"string","const":"canceled","description":"Cancel the appointment. canceled (one L) is the only accepted value; the block then reads blockType canceled."},"reason":{"description":"Why the appointment is cancelled. Appended to the appointment's notes and recorded in the activity log.","type":"string","minLength":1,"maxLength":1000}},"required":["blockType"],"additionalProperties":false,"description":"Cancellation. Returns the visit to unscheduled; an already cancelled block is returned unchanged."}],"description":"Change to a confirmed appointment: a move or reassignment, or a cancellation with blockType canceled. notes is accepted only with a move or reassignment; reason only with blockType."},"UpdateContactRequest":{"type":"object","properties":{"preferredContactMethod":{"description":"The contact's preferred communication method: phone, text, or email. Maintained in Mason and not written to your property management system.","type":"string","enum":["phone","text","email"]},"language":{"description":"The contact's preferred language: a lowercase language code with optional subtags, such as en, es, or en-US, 2-16 characters. Maintained in Mason and not written to your property management system.","type":"string","minLength":2,"maxLength":16,"pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$"},"stopAllComms":{"description":"true blocks every Mason-initiated text, email, call, and group-chat add to this contact, and to any other contact in your account with the same phone number or email address. It does not stop inbound replies: messages from the contact still reach Mason. false removes this contact's block. Maintained in Mason and not written to your property management system.","type":"boolean"},"notes":{"description":"Internal notes about this contact, shown to the Mason team and Mason's agents and never to the contact, 1-5000 characters. Replaces the current notes; null clears them. Maintained in Mason and not written to your property management system.","anyOf":[{"type":"string","minLength":1,"maxLength":5000},{"type":"null"}]}},"additionalProperties":false,"description":"Mason-maintained contact fields to change. Omitted fields are left unchanged. Fields that come from your property management system cannot be changed here.","minProperties":1},"UpdateUnitRequest":{"type":"object","properties":{"access":{"type":"object","properties":{"gateCode":{"description":"Gate code, 1-64 characters. null clears it.","anyOf":[{"type":"string","minLength":1,"maxLength":64},{"type":"null"}]},"lockboxCode":{"description":"Lockbox code, 1-64 characters. null clears it.","anyOf":[{"type":"string","minLength":1,"maxLength":64},{"type":"null"}]},"alarmCode":{"description":"Alarm code, 1-64 characters. null clears it.","anyOf":[{"type":"string","minLength":1,"maxLength":64},{"type":"null"}]},"notes":{"description":"Access notes, such as where the lockbox is or how to reach the entrance, 1-2000 characters. null clears them.","anyOf":[{"type":"string","minLength":1,"maxLength":2000},{"type":"null"}]}},"additionalProperties":false,"description":"Access details. Maintained in Mason for this record and not written to your property management system. Not yet included in vendor or technician dispatches; that is a separate change. Send at least one key: omitted keys are left unchanged and null clears a key.","minProperties":1}},"required":["access"],"additionalProperties":false,"description":"Mason-maintained unit fields to change. Omitted fields are left unchanged. Fields that come from your property management system cannot be changed here."},"UpdatePropertyRequest":{"type":"object","properties":{"access":{"type":"object","properties":{"gateCode":{"description":"Gate code, 1-64 characters. null clears it.","anyOf":[{"type":"string","minLength":1,"maxLength":64},{"type":"null"}]},"lockboxCode":{"description":"Lockbox code, 1-64 characters. null clears it.","anyOf":[{"type":"string","minLength":1,"maxLength":64},{"type":"null"}]},"alarmCode":{"description":"Alarm code, 1-64 characters. null clears it.","anyOf":[{"type":"string","minLength":1,"maxLength":64},{"type":"null"}]},"notes":{"description":"Access notes, such as where the lockbox is or how to reach the entrance, 1-2000 characters. null clears them.","anyOf":[{"type":"string","minLength":1,"maxLength":2000},{"type":"null"}]}},"additionalProperties":false,"description":"Access details. Maintained in Mason for this record and not written to your property management system. Not yet included in vendor or technician dispatches; that is a separate change. Send at least one key: omitted keys are left unchanged and null clears a key.","minProperties":1},"pauseOwnerOutreach":{"description":"true mutes every Mason-to-owner message about this property: owner approvals, dispatch and completion emails, estimate emails, and agent owner messages. Owner messages your team explicitly asks Mason to send are still sent. While paused, work that needs owner approval cannot get it through Mason. false resumes owner messages. This is the same setting as the Pause owner outreach switch on the Mason property page. Maintained in Mason and not written to your property management system.","type":"boolean"}},"additionalProperties":false,"description":"Mason-maintained property fields to change. Omitted fields are left unchanged. Fields that come from your property management system cannot be changed here.","minProperties":1},"CreateContactRequest":{"type":"object","properties":{"contactType":{"type":"string","const":"vendor","description":"The kind of contact to create. vendor is the only value."},"name":{"type":"string","minLength":1,"maxLength":200,"description":"The vendor's business name, 1-200 characters, such as Example Plumbing Co. Mason converts an all-capital or all-lowercase name to title case. Put the person you deal with in firstName and lastName."},"firstName":{"description":"The first name of your contact person at the vendor, 1-100 characters. Sent to AppFolio as the vendor's contact first name when your account is connected to AppFolio; not stored for RentVine or Mason-only vendors.","type":"string","minLength":1,"maxLength":100},"lastName":{"description":"The last name of your contact person at the vendor, 1-100 characters. Sent to AppFolio as the vendor's contact last name when your account is connected to AppFolio; not stored for RentVine or Mason-only vendors.","type":"string","minLength":1,"maxLength":100},"phoneNumber":{"description":"The vendor's US phone number, such as (555) 555-0188 or +15555550188. Mason stores it in E.164 form (+15555550188); a value that is not a valid 10-digit US number returns 400.","type":"string","minLength":1,"maxLength":40},"email":{"description":"The vendor's email address.","type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":["contactType","name"],"additionalProperties":false,"description":"The contact to create. Only vendor contacts can be created today: send contactType \"vendor\", name, and at least one of phoneNumber or email.","anyOf":[{"required":["phoneNumber"]},{"required":["email"]}]}}}}