PUT /v1/properties/{provider_id} pushes one property into Maat. The provider_id in
the path is your identifier — unique within your integration, never across the
platform — which makes the operation idempotent by construction: retrying a timed-out
push is always safe, and there is no idempotency header to remember.
What provider_id may contain: any non-empty string of at most 128 characters, url
-encoded in the path. It is opaque to us — we never parse it, never derive anything from it,
and never show it to anyone else. Use whatever your own system already calls the property;
two integrations may use the same string for different properties and neither will ever see
the other’s.
The response
result is created or updated. property_id and unit_id are always present —
they are the handles the
targeted edits take. listing_id is
null until the property is complete enough to have one. The reference carries the same
sample in Node and Go.
Replace, not merge
The payload you send is the whole property. An amenity you omit is removed; a photo you omit is dropped. This mirrors how listings are edited everywhere on Maat, and it is the only version of “update” in which remove this amenity is expressible at all. The practical consequence: build your push from your own catalogue every time, never from a diff.A property can be accepted and not yet sellable
A property with no price, no photos or no amenities is accepted and held in an incomplete state rather than published at a placeholder price. The response tells you exactly where it stands:
Branch on
missing, and treat its two photo values differently — they ask for opposite
things:
photos_processingmeans wait. Photos are fetched asynchronously, so the first push of a complete property legitimately comes backpublishable: false. There is nothing to do; we fetch, process and publish on our own.photosmeans send more. The property does not have enough usable images.
Photos are URLs, and unchanged URLs are free
You send photo URLs; Maat fetches each one and runs it through the same processing pipeline a host upload goes through. Three rules follow:- URLs must be
https, on a public DNS name, with no redirects. Anything else comes back inphotos_rejectedasurl_refused— and the reason never says more than that, by design. - An unchanged URL is never re-fetched, so a nightly catalogue sync costs nothing for the photos that did not change.
- Changed image bytes need a new URL. We treat the URL as the identity of the photo; publish edited images at a fresh path.
position: 0 is the cover photo. Per-photo failures are named individually in
photos_rejected (url_refused, fetch_failed, unsupported_type, too_large,
processing_failed), so one dead CDN path in a thirty-photo push is findable.
The address is where the property is — not how to get in
Send only the address fields in the schema. Delivery detail — building, floor, apartment number, directions to the key box — is not part of this contract in either direction, because it is private to the host and the confirmed guest. A payload carrying such a field is refused withvalidation_failed, not silently
trimmed.
Taking a property off sale
status: "unlisted" makes the property unsellable on Maat without deleting anything.
The response reports unlisted in missing[] alongside any real deficiency, so you
always know whether the property is otherwise complete before you re-list it. There is
no property deletion in the current contract.
Current status
Live in the sandbox: a sandbox token creates real properties in your sandbox workspace. Against a production workspace the request is authenticated and validated in full, then answers501 — see Environments.