Conventions
Rules that hold everywhere in this API. Reading this page once saves reading it inline on every other page.
The response envelope
Every response — success or failure — is a JSON object with success and
message. Successes add data. Failures add a machine-readable
code, and sometimes errors.
{
"success": true,
"message": "OK",
"data": [
"..."
]
}
{
"success": false,
"code": "UNIT_INACTIVE",
"message": "units.0 refers to a unit that is no longer sellable.",
"errors": {
"units.0": {
"inventory_id": 31,
"is_active": false
}
}
}
Branch on code, never on message. Messages are written for humans
and may be reworded; codes are part of the contract. Every code is listed on the
errors page.
pagination and cursor are siblings of data, not children
data — not inside it. Reaching for data.pagination gets you
null.{
"success": true,
"message": "OK",
"data": [
"...",
"..."
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 128,
"last_page": 3
}
}
Dates and times
| Field | Type | Description |
|---|---|---|
Calendar dates
|
string | Always YYYY-MM-DD. Used for check_in, check_out, dates[].date and every window. |
Timestamps
|
string | ISO-8601 with an offset, e.g. 2026-10-01T16:22:40+05:30. |
Timestamps are in India Standard Time, not UTC
Asia/Kolkata and serialises timestamps with that offset
(+05:30). They are unambiguous — the offset is right there — but they are not
UTC-normalised, so parse the offset rather than assuming a Z.check_out is exclusive. A stay from the 12th to the 14th is two
nights, the 12th and the 13th; the guest leaves on the morning of the 14th. Date windows in
webhooks, by contrast, are inclusive at both ends and list nights: a window of
2026-10-12 to 2026-10-13 covers exactly those two nights.
Money
Every amount is in Indian rupees. currency is present, and is always
"INR".
Amounts are JSON numbers, not fixed-decimal strings
13000.00 is serialised as 13000 and 8000.50 as
8000.5. Parse numerically. Do not assume two decimal places, and do not compare
amounts as strings.Amounts are in rupees, not paise. There is no minor-unit integer anywhere in this API.
GST
Whether a price includes GST depends on the property, and it is not a constant. The
rates.changed
payload carries both flags you need: gst_applicable (does this seller charge GST at
all) and price_includes_gst (is it already inside base_price). Read
both before you display or re-sell a price.
Identifiers
Most things have two ids: Doorloom's, and yours.
| Field | Type | Description |
|---|---|---|
doorloom_id
|
integer | Doorloom's permanent id for a property. Never changes. |
external_id
|
string|null | Your id for that property, if Doorloom staff mapped one. Null when unmapped. |
inventory_id
|
integer | Doorloom's permanent id for a unit. |
external_unit_id
|
string|null | Your id for that unit, if mapped. |
external_booking_id
|
string | Your id for a booking. You supply it at create; it is unique within your integration. |
Event id
|
string | A ULID, unique for the lifetime of the integration. Useful as a log key; it is not a sequence. |
Where a path takes {property} you may pass either the Doorloom id or your
external id, and Doorloom resolves whichever it recognises. Booking paths are stricter: the
numeric path takes Doorloom's id, and a separate path exists for looking a booking up by yours.
Request format
Send Content-Type: application/json on every request with a body. Send
Accept: application/json always. Unknown fields in a request body are rejected only
where a validation rule covers them; do not rely on either behaviour — send what is documented.
Compatibility
Within API version 2026-09, changes are additive
only. New fields may appear in a response or an event payload at any time. Existing
fields will not change type or meaning, and will not be removed.
So: ignore fields you do not recognise, and never assert on the exact set of keys in a payload. A breaking change means a new version, and we would talk to you before it happened.