Enquiries Channel manager Bookings Your website Booking engine Pricing Log in Sign up
v2026-09

Update a property

Change a property you cover: its listing facts, address, base rates, units and your external id for it. Send only the groups you want to change — everything you omit is left exactly as it is — and the response is the property block as GET /properties returns it.

PUT https://doorloom.com/api/integrations/v1/properties/{property}

{property} is the Doorloom id or your external_id; Doorloom resolves whichever it recognises. The property must be in your active coverage — one that Doorloom staff removed from your integration is a 404, and an archived one is 422 PROPERTY_ARCHIVED.

Headers

Field Type Required Description
Authorization string Required Bearer <your API key>.
Content-Type string Required application/json.

No idempotency key, no If-Match

A PUT here is naturally idempotent: applying the same body twice reaches the same state, and units are addressed by id so a retried request cannot create a duplicate. Properties carry no revision counter, so there is no If-Match: the last write wins, whether it came from you or from the host in the Doorloom app.

Request body

Every field is optional. A group that is present is applied; a group that is absent is untouched. Field rules are the same as on create unless noted.

Body

Field Type Required Description
external_id string|null Optional Re-map your id for this property. null clears the mapping. An id already mapped to another of your properties is a 409.
name string Optional The listing name.
property_type string|null Optional One of the listed types, or null to clear.
property_category string|null Optional vacation_rental, resort_hotel or null.
description string Optional Max 2000 characters.
address object Optional Any subset of the address fields. Omitted fields keep their value; formatted_address is re-derived unless you send it.
space object Optional bedrooms and/or washrooms.
occupancy object Optional min_guests and/or max_guests.
pricing object Optional weekday and/or weekend, each with any subset of base_price, per_night_occupancy, extra_adult_price, extra_child_price.
units array Optional 1 to 50 entries. A merge list: each entry changes or creates one unit; units you do not mention are untouched.
units[].inventory_id integer one of the two Address the unit by Doorloom's id.
units[].external_id string|null one of the two Address the unit by your alias. An alias Doorloom does not know creates the unit (name required). With inventory_id as well, sets or changes that unit's alias; null clears it.
units[].name string Optional Rename. Required when the entry creates a unit.
units[].code string|null Optional Max 64 characters.
units[].max_occupancy integer|null Optional Guests the unit sleeps.
units[].is_active boolean Optional false takes the unit off sale, true puts it back. The default unit cannot be deactivated.
features object Optional Any subset of the features fields.

Example

Request bash
curl -X PUT https://doorloom.com/api/integrations/v1/properties/VILLA-001 \
  -H "Authorization: Bearer $DOORLOOM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Amber Villa by the Sea",
    "pricing": { "weekend": { "base_price": 16500 } },
    "units": [
      { "inventory_id": 3101, "name": "Sea View Suite", "external_id": "U-SEA" },
      { "external_id": "U-GARDEN", "is_active": false },
      { "external_id": "U-ATTIC", "name": "Attic Room", "max_occupancy": 2 }
    ]
  }'

Three things happen to the units: unit 3101 is renamed and given the alias U-SEA; the unit already aliased U-GARDEN is taken off sale; and because U-ATTIC is not yet an alias of this property, a new unit is created and mapped to it. The address, the weekday rate and every other unit are untouched.

Response

Response 200 json
{
    "success": true,
    "message": "Property updated",
    "data": {
        "doorloom_id": 902,
        "external_id": "VILLA-001",
        "coverage": "active",
        "name": "Amber Villa by the Sea",
        "property_type": "villa",
        "status": "active",
        "is_master": true,
        "master_property_id": 902,
        "units": [
            {
                "inventory_id": 3101,
                "external_unit_id": "U-SEA",
                "name": "Sea View Suite",
                "code": "SEA",
                "is_active": true,
                "is_default": true,
                "max_occupancy": 4,
                "deleted": false
            },
            {
                "inventory_id": 3104,
                "external_unit_id": "U-ATTIC",
                "name": "Attic Room",
                "code": null,
                "is_active": true,
                "is_default": false,
                "max_occupancy": 2,
                "deleted": false
            }
        ]
    }
}

units[] lists active units only, as on GET /properties; the deactivated U-GARDEN unit is absent here and present, flagged, on the inventory.changed event that follows.

Units

  • Address every entry by inventory_id or external_id. An entry with neither is a 422 on units.N — that is what keeps a retried request from adding the same unit twice.
  • A property always keeps its default unit active; sending is_active: false for it is a 422 on units.N.is_active. To retire it, the host promotes another unit in the Doorloom app first.
  • Units are never deleted through the API; deactivate them instead. Bookings against a deactivated unit keep their history.
  • An inventory_id that belongs to another property is a 422 on units.N.inventory_id; an alias already mapped to another property's unit is a 422 on units.N.external_id.

What happens afterwards

A successful update always emits property.changed for the property. If you changed prices you also receive rates.changed; if you touched units, inventory.changed and, when a unit went on or off sale, availability.changed across your horizon. These are your own writes echoed back as full state; apply them by the sequence rule like any other event.

Errors

Errors

Status Code Meaning
422 VALIDATION_FAILED The request body failed validation. errors is Laravel's field bag: an object keyed by field path, each holding an array of messages.
404 NOT_FOUND No such booking or property for this integration. Another integration's booking or property is not found rather than forbidden, so ids cannot be probed across partners. On a property write, a property whose coverage staff have removed is also not found.
422 PROPERTY_ARCHIVED The property exists and is covered, but the host has archived it. Archived properties are off-market: they cannot take bookings, and they cannot be edited through the API.
409 PROPERTY_EXTERNAL_ID_EXISTS The external_id you sent is already mapped to a property of your integration. On a create, that property was not created; on an update, the mapping was not changed. errors.doorloom_id tells you which property holds the id, so you can store the mapping or pick a different id.
409 IN_PROGRESS An identical request is still being processed. Two requests raced; the first one is still inside its transaction.
429 RATE_LIMITED You exceeded one of the rate limits. The standard Retry-After and X-RateLimit-* headers are set on the response.
401 UNAUTHENTICATED No API key, or a key that is not valid. Rotating your API key invalidates the previous one immediately.
403 NOT_INTEGRATION_TOKEN The bearer token is valid but is not an integration API key — it belongs to another Doorloom token surface. Integration keys are the only credential this API accepts.
403 INTEGRATION_DISABLED Doorloom staff disabled this integration. No events are recorded and no API call succeeds. This is distinct from paused: a paused integration keeps full API access and only stops receiving webhooks.

Retrying

Every retry of an unchanged PUT is safe: a timeout, a 5xx or a 409 IN_PROGRESS can simply be resent. A 4xx other than those means the body is wrong or the property is gone from your scope; fix the cause rather than retrying.

Something unclear or wrong on this page? Write to [email protected] and tell us which page — we would rather fix the doc than answer the ticket twice.