API reference
Job requests
Resource jobRequests
A job request invites service providers to a job at a property. The engine runs synchronously and returns the job snapshot; the lifecycle then continues over webhooks.
Create a job request
/v1/jobRequests 201 Created
x-api-key
The job engine runs synchronously and the rebuilt job snapshot is returned inline; validation problems come back as HTTP 400. The snapshot starts pending. Acceptance, start, and completion arrive later as webhooks.
| Field | Type | Required | Notes |
|---|---|---|---|
serviceProviders | object[] | Required | Non-empty. Items { "email": string }: the providers invited to the job. |
time | object | Required | See Job time. |
property | object | Required | Identifies the property and can update its details in the same call. See Job property. |
checklists | object[] | Optional | Items { "checklistId": string }. |
offeredPrice | number | Optional | 0 or more. |
offeredPriceCurrency | string | Optional | — |
message | string | Optional | 3–1500 chars, shown to the providers. |
sourceBookingId | string | Optional | Links the job to a booking. |
receiveUpdates | boolean | Optional | — |
Job time
| Field | Type | Required | Notes |
|---|---|---|---|
type | string | Required | fixed or flexible. |
startTime | date-time | Required | — |
endTime | date-time | Optional | — |
durationInHours | integer | Optional | 1–999. Omit it rather than sending 0. |
durationInMinutes | integer | Optional | 1–999. Omit it rather than sending 0. |
Job property
| Field | Type | Required | Notes |
|---|---|---|---|
propertyId | string | One of | Min 3 chars. One of propertyId or sourcePropertyId. |
sourcePropertyId | string | One of | Min 3 chars. |
information | string | Optional | — |
access | string | Optional | — |
garbage | string | Optional | — |
parking | string | Optional | — |
wifiName | string | Optional | — |
wifiPassword | string | Optional | — |
wifiDescription | string | Optional | — |
otherAttributes | object[] | Optional | See Job other attributes. |
Job other attributes
| Field | Type | Required | Notes |
|---|---|---|---|
label | string | Required | Max 60 chars. |
value | string | string[] | Required | A string of up to 100 chars, or an array of such strings. |
group | string | Optional | Max 100 chars. |
pictures | string[] | Optional | Picture URLs. |
curl -X POST https://platform.getproperly.com/v1/jobRequests \
-H "x-api-key: $PROPERLY_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: 018f6b1e-job-turnover-1003" \
-d '{
"serviceProviders": [{ "email": "cleaner@example.com" }],
"time": { "type": "flexible", "startTime": "2026-10-08T11:00:00Z",
"endTime": "2026-10-08T15:00:00Z", "durationInHours": 3 },
"property": { "sourcePropertyId": "pms-100234" },
"checklists": [{ "checklistId": "chk_9RtV" }],
"offeredPrice": 90, "offeredPriceCurrency": "USD",
"message": "Turnover clean after the Smith stay, please verify the balcony.",
"sourceBookingId": "pms-bk-55871"
}' List job requests in a date window
/v1/jobRequests 200 OK
x-api-key
Cursor-paginated job rows in the window, in the collection envelope, ordered by scheduledStartTime ascending with ties broken by id. In the legacy API this was an async webhook flow; here it is a plain query. Invalid dates or a malformed cursor → 400.
| Parameter | Type | Required | Notes |
|---|---|---|---|
dateFrom | date-time | Required | — |
dateTo | date-time | Required | — |
status | integer | Optional | See Job status numbers. Use 1 for jobs that still need a cleaner. Any other value is a 400. |
cursor | string | Optional | Opaque cursor from a previous page's nextCursor. |
limit | integer | Optional | 1–100, default 50. |
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job id. |
status | integer | Optional | See Job status numbers. |
jobType | string | Optional | — |
title | string | Optional | — |
note | string | Optional | — |
createdTime | date-time | Optional | — |
scheduledStartTime | date-time | Optional | — |
scheduledEndTime | date-time | Optional | — |
actualStartTime | date-time | Optional | — |
actualEndTime | date-time | Optional | — |
hostId | string | Optional | — |
propertyId | string | Optional | — |
propertyTitle | string | Optional | — |
address | object | Optional | { street, apt, city, state, zip, country, AddressArray }. |
location | number[] | Optional | [longitude, latitude]; entries may be null. |
checklists | string[] | Optional | Ids of the checklists attached to the job. |
cleanerId | string | null | Optional | — |
cleanerEmail | string | null | Optional | — |
cleanerName | string | null | Optional | — |
partnerBookingId | string | Optional | Present only when the job is linked to a partner booking. |
offeredPrice | number | Optional | — |
offeredPriceCurrency | string | Optional | — |
verification | object | Optional | Progress evidence. See Verification under Get a job request. |
curl "https://platform.getproperly.com/v1/jobRequests?dateFrom=2026-10-01T00:00:00Z&dateTo=2026-10-31T23:59:59Z&status=1&limit=50" \
-H "x-api-key: $PROPERLY_API_KEY" {
"data": [
{
"jobRequestId": "jr_5TzK…",
"status": 1,
"jobType": "cleaning",
"title": "Turnover clean",
"scheduledStartTime": "2026-10-08T11:00:00.000Z",
"scheduledEndTime": "2026-10-08T15:00:00.000Z",
"propertyId": "8jL2mQxT4a",
"propertyTitle": "Seaside Loft 2B",
"cleanerId": null,
"cleanerEmail": null,
"cleanerName": null,
"partnerBookingId": "pms-bk-55871",
"offeredPrice": 90,
"offeredPriceCurrency": "USD",
"verification": {
"completedTaskCount": 0,
"totalTaskCount": 15,
"verificationPictureCount": 0,
"requiredVerificationPictureCount": 10,
"problemCount": 0
}
}
],
"nextCursor": "jr_5TzK…",
"hasMore": true
} Job status numbers
Used by the status filter above and returned as status on every job
row, single and listing.
| status | Meaning |
|---|---|
1 | Sent to cleaners; no cleaner has accepted yet |
2 | Accepted by a cleaner |
3 | Cancelled by the host |
4 | Declined by every invited cleaner |
5 | In progress — the cleaner has started |
7 | Finished |
8 | Cancelled by the cleaner |
9 | Waiting for the cleaner to accept changes made after they accepted the job |
-
9appears when a job changes after a cleaner accepted it — whether the change was made in the Properly app or throughPATCH /v1/jobRequests/{jobRequestId}. The cleaner stays assigned; the job returns to2when they accept the changes, or to1if they decline them. -
To find jobs that still need a cleaner, filter with
status=1. -
Any other
statusfilter value is rejected with a 400.
Get a job request
/v1/jobRequests/{jobRequestId} 200 OK
x-api-key
Returns the current job row, keyed by jobRequestId (job reads never expose an _id or jobId). 404 if the job does not exist or is not owned by your account.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job id. |
status | integer | Optional | See Job status numbers. |
jobType | string | Optional | — |
title | string | Optional | — |
note | string | Optional | — |
createdTime | date-time | Optional | — |
scheduledStartTime | date-time | Optional | — |
scheduledEndTime | date-time | Optional | — |
actualStartTime | date-time | Optional | — |
actualEndTime | date-time | Optional | — |
hostId | string | Optional | — |
propertyId | string | Optional | — |
propertyTitle | string | Optional | — |
address | object | Optional | { street, apt, city, state, zip, country, AddressArray }. |
location | number[] | Optional | [longitude, latitude]; entries may be null. |
checklists | string[] | Optional | Ids of the checklists attached to the job. |
cleanerId | string | null | Optional | — |
cleanerEmail | string | null | Optional | — |
cleanerName | string | null | Optional | — |
partnerBookingId | string | Optional | Present only when the job is linked to a partner booking. |
offeredPrice | number | Optional | — |
offeredPriceCurrency | string | Optional | — |
verification | object | Optional | Progress evidence. See Verification under Get a job request. |
Verification
Every job read carries a verification object: the evidence of how the job went. The cleaner's actual coordinates are never returned.
| Field | Type | Required | Notes |
|---|---|---|---|
completedTaskCount | integer | Optional | Each verification photo taken counts as a completed task. |
totalTaskCount | integer | Optional | Includes one task per checklist step that requires a verification photo: 8 tasks and 2 photo steps total 10. |
verificationPictureCount | integer | Optional | — |
requiredVerificationPictureCount | integer | Optional | — |
problemCount | integer | Optional | — |
problems | array | Optional | Present only when the cleaner reported any. See Problem entry. |
startDistanceMeters | integer | Optional | How far the cleaner was from the property when starting. Omitted when no location was recorded. |
endDistanceMeters | integer | Optional | How far the cleaner was when finishing. Omitted when no location was recorded. |
Problem entry
The cleaner's written description of the problem and any photos attached to it are not returned.
| Field | Type | Required | Notes |
|---|---|---|---|
severity | integer | Optional | 0-5 as recorded in Properly. Properly's own apps show 4-5 as High, 3 as Moderate, 1-2 as Low, and no label at 0. |
status | string | Optional | open, inProgress, resolved, or ignored. |
step | string | Optional | The checklist step the problem was reported against. |
checklist | string | Optional | The checklist that step belongs to. |
reportedAt | date-time | Optional | — |
curl https://platform.getproperly.com/v1/jobRequests/jr_5TzK \
-H "x-api-key: $PROPERLY_API_KEY" {
"jobRequestId": "jr_5TzK…",
"status": 7,
"jobType": "cleaning",
"title": "Turnover clean",
"scheduledStartTime": "2026-10-08T11:00:00.000Z",
"actualStartTime": "2026-10-08T11:04:12.000Z",
"actualEndTime": "2026-10-08T13:41:55.000Z",
"propertyId": "8jL2mQxT4a",
"propertyTitle": "Seaside Loft 2B",
"cleanerEmail": "cleaner@example.com",
"cleanerName": "Maria Lopez",
"partnerBookingId": "pms-bk-55871",
"verification": {
"completedTaskCount": 12,
"totalTaskCount": 15,
"verificationPictureCount": 8,
"requiredVerificationPictureCount": 10,
"problemCount": 1,
"problems": [
{
"severity": 4,
"status": "open",
"step": "Clean the oven",
"checklist": "Standard turnover",
"reportedAt": "2026-09-21T10:14:00.000Z"
}
],
"startDistanceMeters": 40,
"endDistanceMeters": 35
}
} Update a job request
/v1/jobRequests/{jobRequestId} 200 OK
x-api-key
Partial update; returns the rebuilt snapshot. property is details-only here (the seven detail strings plus otherAttributes, no ids) and every field inside time is optional, including type and startTime.
| Field | Type | Required | Notes |
|---|---|---|---|
checklists | object[] | Optional | Items { "checklistId": string }. |
offeredPrice | number | Optional | 0 or more. |
offeredPriceCurrency | string | Optional | — |
message | string | Optional | 3–1500 chars. |
serviceProviders | object[] | Optional | Items { "email": string }. |
receiveUpdates | boolean | Optional | — |
property | object | Optional | Details only: information, access, garbage, parking, wifiName, wifiPassword, wifiDescription, otherAttributes. |
time | object | Optional | Same fields as Job time; all optional. |
curl -X PATCH https://platform.getproperly.com/v1/jobRequests/jr_5TzK \
-H "x-api-key: $PROPERLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "offeredPrice": 100, "message": "Price updated: extra balcony work." }' Add or update one-off tasks
/v1/jobRequests/{jobRequestId}/oneOffTasks 200 OK
x-api-key
Adds or updates extra one-off tasks on the job. Returns the updated snapshot.
| Field | Type | Required | Notes |
|---|---|---|---|
tasks | object[] | Required | See One-off task. |
One-off task
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | Required | — |
note | string | Required | — |
sourcePictureUrl | string | Optional | A URL. |
curl -X POST https://platform.getproperly.com/v1/jobRequests/jr_5TzK/oneOffTasks \
-H "x-api-key: $PROPERLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tasks": [
{ "title": "Replace shower curtain", "note": "New one is in the hall closet." }
]
}' Cancel a job request
/v1/jobRequests/{jobRequestId}/cancel 200 OK
x-api-key
No body. Cancels a job that has not started and returns the snapshot. Subscribed partners also receive the jobRequest.canceled webhook; the same event fires when a host cancels in the Properly UI.
curl -X POST https://platform.getproperly.com/v1/jobRequests/jr_5TzK/cancel \
-H "x-api-key: $PROPERLY_API_KEY" Update payment status
/v1/jobRequests/{jobRequestId}/paymentStatus 200 OK
x-api-key
Updates the payment status associated with the job.
| Field | Type | Required | Notes |
|---|---|---|---|
status | string | Required | One of pending, failed, successful. |
description | string | Optional | — |
curl -X PATCH https://platform.getproperly.com/v1/jobRequests/jr_5TzK/paymentStatus \
-H "x-api-key: $PROPERLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "successful", "description": "Paid via PMS payout #8812" }' Job chat
Each job has a chat thread between the host and the provider. Post as the host with JSON or
multipart, and receive provider messages via the comment.new webhook.
Get the job chat
/v1/jobRequests/{jobRequestId}/comments 200 OK
x-api-key
Loads the chat thread for a job in the collection envelope. nextCursor is always null and hasMore always false; page with offset and limit if needed. Unknown job → 404.
| Parameter | Type | Required | Notes |
|---|---|---|---|
updatedAfter | date-time | Optional | Only comments updated after this date-time. |
offset | integer | Optional | 0 or more. |
limit | integer | Optional | 1–100. |
curl "https://platform.getproperly.com/v1/jobRequests/jr_5TzK/comments?limit=50" \
-H "x-api-key: $PROPERLY_API_KEY" Post a comment as the host
/v1/jobRequests/{jobRequestId}/comments 201 Created
x-api-key
Send JSON, or multipart/form-data with a text field message and/or an image file part named file. At least one of message or file is required. Returns the created comment. Image uploads may appear to other apps on the next fetch rather than instantly.
| Field | Type | Required | Notes |
|---|---|---|---|
message | string | One of | At least one of message or file. |
languageCode | string | Optional | e.g. "en". JSON field or multipart text part. |
file | file | One of | Image part; multipart/form-data only. |
- Incoming provider messages arrive via the comment.new webhook.
curl -X POST "https://platform.getproperly.com/v1/jobRequests/jr_5TzK/comments" \
-H "x-api-key: $PROPERLY_API_KEY" \
-F "message=Gate code changed to 8842 for today" \
-F "file=@./gate.jpg"