Getting started
Quickstart
Five steps from a Properly Platform API key to a verified webhook delivery.
1. Get a key
Create a key in the Properly web app under Settings → API & AI assistants.
It is shown once; store it in a secret manager. Send it on every request as the x-api-key
header. Details are on the Authentication page.
2. Create a property
Properties are the root of everything else. Create one and read the response:
it contains the created resource, and you use its propertyId in every dependent
call. You can also reference the property later by the sourceId you set, as
sourcePropertyId.
curl -X POST https://platform.getproperly.com/v1/properties \
-H "x-api-key: $PROPERLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 018f6b1e-create-seaside-loft" \
-d '{
"sourceId": "pms-100234",
"name": "Seaside Loft 2B",
"countryCode": "US",
"timeZone": "America/Los_Angeles",
"location": { "latitude": 34.0119, "longitude": -118.4916 },
"beds": 3,
"bedrooms": 2,
"bathrooms": 2,
"tags": ["beach"],
"details": { "access": "Lockbox code 4821", "wifiName": "SeasideLoft", "wifiPassword": "surf2026" },
"bedDetails": [
{ "bedType": "queen", "twinable": false, "displayLabel": "Master bedroom", "quantity": 1 },
{ "bedType": "sofabed", "twinable": false, "displayLabel": "Living room", "quantity": 1 }
]
}' {
"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"
}
The optional Idempotency-Key header makes the request safe to retry. See
Idempotency.
3. Register a webhook
One subscription per destination URL. The response includes the signingSecret only this once; store it server-side before doing anything else.
curl -X POST https://platform.getproperly.com/v1/webhooks \
-H "x-api-key: $PROPERLY_API_KEY" -H "Content-Type: application/json" \
-d '{ "url": "https://example.com/properly/webhooks",
"eventFilters": ["jobRequest.*", "comment.new"] }' {
"id": "sub_9WqAb2cD",
"url": "https://example.com/properly/webhooks",
"eventFilters": ["jobRequest.*", "comment.new"],
"enabled": true,
"maxRetries": 5,
"createdAt": "2026-09-16T10:02:11.000Z",
"signingSecret": "bXlfc2lnbmluZ19zZWNyZXRfMzJfYnl0ZXNfbG9uZyE"
} eventFilters accepts exact event names, prefix wildcards such as
"jobRequest.*", or "*" for everything. The full list is in the
event catalog.
4. Test and verify
Fire a synthetic delivery at your receiver. It is signed with your real secret and flagged
"test": true.
curl -X POST https://platform.getproperly.com/v1/webhooks/sub_9WqAb2cD/test \
-H "x-api-key: $PROPERLY_API_KEY" -H "Content-Type: application/json" \
-d '{ "eventName": "property.create" }' { "deliveryId": "whd_8FkQz31M", "status": "pending" }
Verify the webhook-signature header against the raw request bytes with the
paste-ready verifier on the Webhooks page. The
delivery also appears in the delivery log.
5. Ordering matters
Create the property first, then the pictures, checklists, bookings, and job requests that reference it. Each create returns the created resource synchronously, so the id you need for the next call is in the previous response.
Request conventions
-
Content type is
application/json(UTF-8). Dates in and out are ISO 8601 strings; date inputs are parsed from ISO 8601. - Bodies are strict. Unknown fields in a request body are rejected with a 400 that names each offending field. Send exactly what the reference lists.
- Create endpoints return the created resource, including its server-assigned id, in the 201 body. Update endpoints return the updated resource. Deletes return 204 with no body.
- IDs are opaque strings.
-
Every list endpoint returns the collection envelope
{ data, nextCursor, hasMore }. PassnextCursoras the next request's cursor whilehasMoreis true; unpaginated lists returnnextCursor: nullandhasMore: false. -
Responses carry
X-RateLimit-*headers andx-request-id. You may send your ownx-request-idrequest header; it is echoed back, otherwise one is generated. Include the request id when contacting support.
# Every route except GET /v1/health needs the key
curl https://platform.getproperly.com/v1/health