availability.changed
How many units are sellable each night.
When it fires
A booking was made, changed or cancelled; a date was blocked or unblocked; a checkout hold was taken; the per-date on-sale cap changed; or the unit list changed.
This event is date-scoped: it carries a window, and
data.dates[] has one entry per night in that window, inclusive of both ends. A
window never spans more than one calendar month, so a change across a longer range arrives as
several events.
What to do with it
available_unitsuses direct-booking semantics — the same count the brand's own website sells against. Property-wide blocks, per-unit blocks, non-cancelled bookings, live checkout holds and the per-date cap are all already subtracted. Do not subtract them again.is_blockedmeans *nothing can be sold that night because of a block*, which is not the same as being sold out. A fully booked night hasavailable_units: 0andis_blocked: false.- Doorloom keeps two separate notions of a block.
is_blockedis the one that actually stops a booking.block_scopeis the host's intent, andota_onlydeliberately does not stop a direct booking.
The data block
| Field | Type | Description |
|---|---|---|
total_units
|
integer | Count of active units at the property right now. |
units[]
|
array | The active units, so you can resolve ids without a second call. Same shape everywhere it appears. |
units[].inventory_id
|
integer | Doorloom's permanent id for the unit. |
units[].external_unit_id
|
string|null | Your alias for it, if one has been mapped. Null means unmapped — you can still book the unit by inventory_id, or omit both and let Doorloom allocate. |
units[].name
|
string | Host-facing unit name, e.g. "Garden Suite". |
units[].code
|
string|null | Host-entered short code, if any. |
units[].is_active
|
boolean | False for a unit the host deactivated or deleted. An inactive unit cannot be booked. |
units[].is_default
|
boolean | True for the property's default unit. Single-unit properties have exactly one. |
units[].max_occupancy
|
integer|null | Maximum guests the unit sleeps. Null means the host has not set one; Doorloom does not enforce it. |
units[].deleted
|
boolean | True once the host deletes the unit. Retire your alias when you see this. |
dates[].date
|
string | Y-m-d. One entry per night in window, inclusive of both ends. |
dates[].available_units
|
integer | Units sellable that night, 0 to total_units. |
dates[].total_units
|
integer | Repeated per night so a single row is self-contained. |
dates[].is_blocked
|
boolean | True when a block makes the night unsellable. |
dates[].block_scope
|
string|null | null, "ota_only" or "everywhere". The host's stated intent for the block. |
dates[].units_cap
|
integer|null | Per-date cap on how many units may be sold, if the host set one. Already reflected in available_units. |
Example
The full envelope, as it arrives on the wire.
{
"id": "01J6Y0Q8ZK3N4V6M7P8R9S0T1U",
"type": "availability.changed",
"version": "2026-09",
"sequence": 1042,
"occurred_at": "2026-10-01T15:04:11+05:30",
"integration": {
"id": 12,
"slug": "acme-pms"
},
"property": {
"doorloom_id": 902,
"external_id": "VILLA-9",
"master_property_id": 902
},
"window": {
"from": "2026-10-12",
"to": "2026-10-15"
},
"data": {
"total_units": 2,
"units": [
{
"inventory_id": 31,
"external_unit_id": "ROOM-A",
"name": "Garden Suite",
"code": "GS",
"is_active": true,
"is_default": true,
"max_occupancy": 4,
"deleted": false
},
{
"inventory_id": 32,
"external_unit_id": "ROOM-B",
"name": "Pool Suite",
"code": "PS",
"is_active": true,
"is_default": false,
"max_occupancy": 4,
"deleted": false
}
],
"dates": [
{
"date": "2026-10-12",
"available_units": 1,
"total_units": 2,
"is_blocked": false,
"block_scope": null,
"units_cap": null
},
{
"date": "2026-10-13",
"available_units": 0,
"total_units": 2,
"is_blocked": false,
"block_scope": null,
"units_cap": null
},
{
"date": "2026-10-14",
"available_units": 0,
"total_units": 2,
"is_blocked": true,
"block_scope": "everywhere",
"units_cap": null
},
{
"date": "2026-10-15",
"available_units": 1,
"total_units": 2,
"is_blocked": false,
"block_scope": "ota_only",
"units_cap": 1
}
]
}
}
Related
- The event envelope — the wrapper
around
data, shared by every event. - Ordering and idempotency — how to decide whether to apply this event.
- Snapshots — pull this same
datablock on demand for any date window.