Skip to main content
PUT
cURL

Authorizations

Authorization
string
header
required

A short-lived partner token, obtained by exchanging your API key at POST /token. Send it as Authorization: Bearer <access_token>.

Tokens live for fifteen minutes by default and never for more than an hour. Mint one per batch of work, not one per request.

The token carries the workspace and the environment its key was issued for. You cannot change either by asking: the exchange ignores everything in the request body for exactly that reason.

It also carries the key's scopes (scope, a list). Every operation names a scope as x-maat-scope, and a token whose key lacks it is refused with 403 insufficient_scope, naming the scope. Scopes are fixed when a key is issued and are re-read from the key on every request, so a key narrowed today is narrowed on its next call — the token's scope is what the key held at exchange time, for your own reading, never what authorizes a request.

x-maat-scope is the floor, and on the quick-action operations it is not the whole requirement. PUT and DELETE /listings/{listing_id}/quick-actions/{template_key} carry rules:write, and additionally require pricing:write when template_key begins pricing. — the capability depends on the template in the path, because a cleaning fee changes what a guest pays and a minimum stay does not. The refusal is the same 403 insufficient_scope, naming pricing:write. The two READS apply the same requirement without erroring: GET /listings/{listing_id}/quick-actions still lists the pricing.* rows but withholds their applied state, and GET /listings/{listing_id}/rules omits the pricing rules entirely and reports pricing_withheld in warnings. These four are the only operations in this document whose requirement is not exactly their x-maat-scope, and each of them says so machine-readably: x-maat-scope-additional lists the second scope it can require and x-maat-scope-additional-when says what happens without it.

Never send it as a cookie or in a query string, and never store it — store the API key, mint tokens from it.

Path Parameters

property_id
string<uuid>
required

Maat's identifier for the property, as returned by GET /properties. Not your own provider_id — the write endpoint is the one keyed on that, which is why this read carries a by-id segment.

Body

application/json

A property's whole address, replaced.

Every member is written on every call — as the value you sent, or as null. One you omit is CLEARED, not kept.

The last four are private delivery detail — which building, which floor, which door — and they are accepted on this contract only. They are not part of the property push.

line1
string
required

Street line.

Required string length: 1 - 200
city
string
required

City or town.

Required string length: 1 - 120
country
string
required

ISO 3166-1 alpha-2, uppercase.

Pattern: ^[A-Z]{2}$
latitude
number
required

The map position, the platform's area assignment and the property's time zone are all re-derived from this pair — do not send them. A pair that falls outside every curated area leaves the area unset, which is not an error.

Required range: -90 <= x <= 90
longitude
number
required

Decimal degrees, WGS 84.

Required range: -180 <= x <= 180
region
string | null

State, province or governorate. Absent or null clears it.

Maximum string length: 120
postal_code
string | null

Absent or null clears it.

Maximum string length: 20
building
string | null

Private delivery detail. Absent or null clears it.

Maximum string length: 200
floor
string | null

Private delivery detail, and a STRING rather than a number — real answers include "G", "Mezzanine" and "3A". Absent or null clears it.

Maximum string length: 40
apartment
string | null

Private delivery detail. Absent or null clears it.

Maximum string length: 40
directions
string | null

Private delivery detail — how to find the door once you are at the building. Absent or null clears it.

Maximum string length: 400

Response

The property, read back after the change.

One property, with its units and their listings.

console_url is a deep link into the Maat host console.

property_id
string<uuid>
required

Maat's id for the property. The id the targeted edits take — never your provider_id.

provider_id
string | null
required

Your identifier for the property, when you pushed it. null when you did not.

property_type
string
required

The property-type slug, from GET /catalog/property-types.

address
PropertyReadAddress · object
required

Where the property is.

The last four members are private delivery detail a host typed for the guest who has to find the door. Keep them out of anything your system publishes.

timezone
string | null
required

IANA zone.

Example:

"Africa/Cairo"

amenities
string[]
required

Building-level amenity slugs: every slug offered by at least one of this property's units, de-duplicated. For a property that is one unit — which is every property the write operations accept — it is exactly that unit's set, so PUT /v1/properties/{property_id}/amenities and this field agree. The per-unit sets are still on each unit. A hotel's own facilities (property-scoped amenities) are not on this contract yet.

units
Unit · object[]
required

The physical inventory under the property. One today for anything this API can create.

publishable
boolean
required

True when every listing under this property satisfies the gate.

missing
enum<string>[]
required

The de-duplicated union of its listings' reasons.

See MissingReason.

Why a listing is not publishable. A closed vocabulary.

Available options:
price,
amenities,
cover_photo,
photos,
photos_processing,
unlisted
created_at
string<date-time>
required

When the property was created in Maat.

updated_at
string<date-time>
required

When the property was last changed, by anyone — this API, the host app, or Maat.

console_url
string<uri>

The property's page in the Maat host console.