Webhooks & events
Event catalog
Every event name accepted in eventFilters and delivered as eventName, with the shape of results[0].
Two kinds of events
- API-echo events fire when your API call completes and carry the
operation result. Every subscribed URL receives them, so a second system can mirror what your
integration does. For most of them
results[0]is the same object the HTTP response body carried; the delete events, whose endpoints answer204with no body, carry the deleted resource's id instead, andjobRequest.updateandjobRequest.canceledcarry{ jobRequestId }. Each entry below shows its exact shape. - Lifecycle events fire when people act in Properly's apps: a provider accepts, declines, cancels, starts, or finishes a job, reports a problem, or posts a chat message, and every invited provider declining fires one too. They have no corresponding REST call. Webhooks or the polling feed are the only way to receive them. A host cancelling or editing a job in the UI fires the API-echo names; see Dual-purpose events below.
Full catalog
| Family | Events |
|---|---|
| Property | property.create property.update property.delete |
| Property picture | propertyPicture.create propertyPicture.delete |
| Booking | booking.create booking.update booking.changed booking.canceled booking.delete |
| Checklist | checklist.create checklist.update checklist.disable |
| Reminder | reminder.create reminder.delete |
| Job request (API-echo) | jobRequest.create jobRequest.update jobRequest.oneOffTaskUpdate jobRequest.canceled jobRequest.updatePaymentStatus |
| Job request (lifecycle) | jobRequest.accepted jobRequest.declinedByServiceProvider jobRequest.declinedByAllServiceProviders jobRequest.canceledByServiceProvider jobRequest.started jobRequest.completed jobRequest.problemReported |
| Comment (lifecycle) | comment.new |
API-echo example
For most API-echo events results[0] equals the success response body of the
endpoint that fired it. A property.create delivery after
POST /v1/properties:
{
"clientRequestId": "018f6b1e-create-seaside-loft",
"apiRequestId": "kQ7Lm2…",
"targetAccountId": "oU8C9LsuBw",
"createdAt": "2026-09-16T10:15:04.000Z",
"eventName": "property.create",
"results": [
{
"propertyId": "8jL2mQxT4a",
"sourceId": "pms-100234",
"name": "Seaside Loft 2B",
"address": "12 Ocean Ave, Santa Monica, CA",
"pictureUrls": ["https://res.cloudinary.com/…/prop1.jpg"],
"tags": ["beach"],
"location": { "latitude": 34.0119, "longitude": -118.4916 },
"timeZone": "America/Los_Angeles",
"countryCode": "US",
"bedrooms": 2,
"beds": 3,
"bathrooms": 2,
"bedDetails": [
{ "bedType": "queen", "twinable": false, "displayLabel": "Master bedroom", "quantity": 1 },
{ "bedType": "sofabed", "twinable": false, "displayLabel": "Living room", "quantity": 1 }
],
"details": { "access": "Lockbox code 4821", "wifiName": "SeasideLoft", "wifiPassword": "surf2026" },
"createdAt": "2026-05-02T18:11:04.000Z",
"updatedAt": "2026-08-30T09:20:41.000Z"
}
],
"notifiedAt": "2026-09-16T10:15:05.412Z"
} Property
property.create API echo
POST /v1/properties completes.
results[0] is the success response body of POST /v1/properties.
property.update API echo
PATCH /v1/properties/{propertyId} completes.
results[0] is the success response body of PATCH /v1/properties/{propertyId}.
property.delete API echo
DELETE /v1/properties/{propertyId} completes.
| Field | Type | Required | Notes |
|---|---|---|---|
propertyId | string | Required | The property that was deleted. |
Property picture
propertyPicture.create API echo
POST /v1/propertyPictures completes.
results[0] is the success response body of POST /v1/propertyPictures.
propertyPicture.delete API echo
DELETE /v1/propertyPictures/{pictureId} completes.
| Field | Type | Required | Notes |
|---|---|---|---|
pictureId | string | Required | The picture that was deleted. |
Booking
booking.create API echo
POST /v1/bookings completes.
results[0] is the success response body of POST /v1/bookings.
booking.update API echo
PATCH /v1/bookings/{bookingId} completes.
results[0] is the success response body of PATCH /v1/bookings/{bookingId}.
booking.changed API echo
PATCH /v1/bookings/{bookingId}/dates completes.
results[0] is the success response body of PATCH /v1/bookings/{bookingId}/dates.
booking.canceled API echo
POST /v1/bookings/{bookingId}/cancel completes.
results[0] is the success response body of POST /v1/bookings/{bookingId}/cancel.
booking.delete API echo
DELETE /v1/bookings/{bookingId} completes.
| Field | Type | Required | Notes |
|---|---|---|---|
bookingId | string | Required | The booking that was deleted. |
Checklist
checklist.create API echo
POST /v1/checklists completes.
results[0] is the success response body of POST /v1/checklists.
checklist.update API echo
PATCH /v1/checklists/{checklistId} completes.
results[0] is the success response body of PATCH /v1/checklists/{checklistId}.
checklist.disable API echo
POST /v1/checklists/{checklistId}/disable completes.
results[0] is the success response body of POST /v1/checklists/{checklistId}/disable.
Reminder
reminder.create API echo
POST /v1/reminders completes.
results[0] is the success response body of POST /v1/reminders.
reminder.delete API echo
DELETE /v1/reminders/{reminderId} completes.
| Field | Type | Required | Notes |
|---|---|---|---|
reminderId | string | Required | The reminder that was deleted. |
Job request
jobRequest.create API echo
POST /v1/jobRequests completes.
results[0] is the success response body of POST /v1/jobRequests.
jobRequest.update API echo
PATCH /v1/jobRequests/{jobRequestId} completes, and also when a host edits the job in the Properly UI.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
jobRequest.oneOffTaskUpdate API echo
POST /v1/jobRequests/{jobRequestId}/oneOffTasks completes.
results[0] is the success response body of POST /v1/jobRequests/{jobRequestId}/oneOffTasks.
jobRequest.canceled API echo
POST /v1/jobRequests/{jobRequestId}/cancel completes, and also when a host cancels the job in the Properly UI.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
jobRequest.updatePaymentStatus API echo
PATCH /v1/jobRequests/{jobRequestId}/paymentStatus completes.
results[0] is the success response body of PATCH /v1/jobRequests/{jobRequestId}/paymentStatus.
jobRequest.accepted Lifecycle
A service provider accepts the job.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
serviceProvider | string | Required | The provider's email. |
message | string | Optional | The provider's note; absent when none was given. |
{
"jobRequestId": "jr_5TzK…",
"serviceProvider": "cleaner@example.com",
"message": "Confirmed, I can be there by 11."
} jobRequest.declinedByServiceProvider Lifecycle
A service provider declines the job.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
serviceProvider | string | Required | The provider's email. |
message | string | Optional | The provider's note. |
{
"jobRequestId": "jr_5TzK…",
"serviceProvider": "cleaner@example.com",
"message": "Not available that day."
} jobRequest.declinedByAllServiceProviders Lifecycle
Every invited service provider has declined.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
{ "jobRequestId": "jr_5TzK…" } jobRequest.canceledByServiceProvider Lifecycle
The provider who accepted the job cancels.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
serviceProviderId | string | Required | The canceling provider's id. |
{ "jobRequestId": "jr_5TzK…", "serviceProviderId": "cl_2Wq…" } jobRequest.started Lifecycle
The provider starts work.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
{ "jobRequestId": "jr_5TzK…" } jobRequest.completed Lifecycle
The provider finishes work.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
propertyId | string | Required | — |
propertyTitle | string | Required | — |
jobTitle | string | Required | — |
jobType | string | Required | e.g. "cleaning". |
actualStartTime | date-time | Required | — |
actualEndTime | date-time | Required | — |
serviceProvider | object | Required | { name, email, id }. |
partnerBookingId | string | Optional | Your sourceBookingId; present only when the job is linked to a booking. |
offeredPrice | number | Optional | — |
offeredPriceCurrency | string | Optional | — |
paymentStatus | string | Optional | Present only when a payment status was set. |
checklists | object[] | Required | Per checklist: checklistId, counts (taskGroupsCount, tasksCount, verificationRequiredCount, taskGroupsDoneCount, tasksDoneCount, verificationDoneCount) and taskGroups[]. Each task group carries taskGroupId, note, verificationPictures (one per group, the most recent) and tasks[] of { taskId, doneAt, done }. Every task appears; not-done tasks have done: false. |
problems | object[] | Required | Problems reported during the job: { problemId, title, note, pictures, severity, reportedAt }. |
{
"jobRequestId": "jr_5TzK…",
"propertyId": "8jL2mQxT4a",
"propertyTitle": "Seaside Loft 2B",
"jobTitle": "Turnover clean",
"jobType": "cleaning",
"actualStartTime": "2026-10-08T11:04:12.000Z",
"actualEndTime": "2026-10-08T13:41:55.000Z",
"serviceProvider": { "name": "Maria Lopez", "email": "cleaner@example.com", "id": "cl_2Wq…" },
"partnerBookingId": "pms-bk-55871",
"offeredPrice": 90,
"offeredPriceCurrency": "USD",
"paymentStatus": "pending",
"checklists": [
{
"checklistId": "chk_9RtV",
"taskGroupsCount": 4, "tasksCount": 18, "verificationRequiredCount": 2,
"taskGroupsDoneCount": 4, "tasksDoneCount": 17, "verificationDoneCount": 2,
"taskGroups": [
{
"taskGroupId": "tg_1…",
"note": "",
"verificationPictures": ["https://res.cloudinary.com/…/verify1.jpg"],
"tasks": [
{ "taskId": "t_a1…", "doneAt": "2026-10-08T11:31:02.000Z", "done": true },
{ "taskId": "t_a2…", "doneAt": null, "done": false }
]
}
]
}
],
"problems": [
{ "problemId": "…", "title": "Cracked tile", "note": "…", "pictures": ["…"],
"severity": 3, "reportedAt": "2026-10-08T12:10:00.000Z" }
]
} jobRequest.problemReported Lifecycle
The provider reports a problem during the job.
| Field | Type | Required | Notes |
|---|---|---|---|
jobRequestId | string | Required | The job the event refers to. |
propertyTitle | string | Required | — |
problems | object[] | Required | See Problem item shape. |
{
"jobRequestId": "jr_5TzK…",
"propertyTitle": "Seaside Loft 2B",
"problems": [
{
"problemId": "pr_3Hf…",
"title": "Cracked tile",
"note": "Bathroom floor, next to the shower.",
"pictures": ["https://res.cloudinary.com/…/problem1.jpg"],
"reportedAt": "2026-10-08T12:10:00.000Z",
"severity": 3,
"propertyId": "8jL2mQxT4a",
"sourcePropertyId": "pms-100234",
"serviceProvider": { "name": "Maria Lopez", "email": "cleaner@example.com", "id": "cl_2Wq…" }
}
]
} Comment
comment.new Lifecycle
A service provider posts a chat message on a job.
| Field | Type | Required | Notes |
|---|---|---|---|
results[0] | object | Required | The provider's chat message: the message text, the sender, and the job reference. Fetch the full thread with GET /v1/jobRequests/{jobRequestId}/comments. |
Problem item shape
Each item in problems[] on jobRequest.problemReported:
| Field | Type | Required | Notes |
|---|---|---|---|
problemId | string | Required | — |
title | string | Required | — |
note | string | Required | — |
pictures | string[] | Required | Picture URLs. |
reportedAt | date-time | Required | — |
severity | integer | Required | 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. |
propertyId | string | Required | — |
sourcePropertyId | string | Required | Your property id. |
serviceProvider | object | Required | { name, email, id } of the reporting provider. |
On jobRequest.completed, every task appears (done: false for tasks not
done);
taskId values are the ones from your checklist create and update responses; each
task group carries one verification picture (the most recent); and optional fields (
partnerBookingId, paymentStatus) appear only when applicable.
28 events documented.