Quickstart
Four steps, in the order that finds problems earliest: prove your key works, get your properties into Doorloom, prove you can verify a webhook, then write a booking.
You need an API key and a webhook secret from Doorloom before starting. See Authentication.
The onboarding sequence
End to end, an integration comes alive in this order. Each step is expanded below or on its own page.
- Doorloom activates your integration against one brand and hands you an API key and a webhook secret.
- You call
GET /meto prove the key and read your sequence cursor. - You create or map properties. Listings that live in your system go in
through
POST /properties(or the bulk form); listings the host already made in the Doorloom app are in your coverage or are mapped by staff. - You store the ids — Doorloom's
doorloom_idagainst yourexternal_id, andinventory_idagainst your unit ids. - Units are created or mapped in the same create call, or by staff for app-created listings.
- You load initial state: a created property sends you its own snapshot;
for everything else,
GET /propertiesthen the per-property snapshots. - Webhooks keep the two systems in sync, and
PUT /properties/{id}carries your side's listing changes back. - You create bookings.
1. Prove your key works
curl https://doorloom.com/api/integrations/v1/me \
-H "Authorization: Bearer $DOORLOOM_API_KEY"
A 200 means you are talking to the right environment with a live key. Note two
things in the response: data.webhook.last_sequence, which is the cursor you will
need to stay in sync, and data.covered_properties, which tells you how many
properties this integration can already see.
2. Create or map your properties
If the listing lives in your system first, create it. One call makes the property, its units, its opening rates and your id mapping, and covers it for your integration:
curl -X POST https://doorloom.com/api/integrations/v1/properties \
-H "Authorization: Bearer $DOORLOOM_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2c5d0b7e-1f7a-4c1b-9b3e-3e7d9a4f6c21" \
-d '{
"external_id": "VILLA-9",
"name": "Amber Villa, Alibaug",
"property_type": "villa",
"description": "Sea-facing villa with a private pool.",
"address": { "address_line_1": "12 Kihim Beach Road", "city": "Alibaug", "state": "Maharashtra", "pin_code": "402201" },
"space": { "bedrooms": 3, "washrooms": 3 },
"occupancy": { "max_guests": 8 },
"pricing": { "weekday": { "base_price": 12000 }, "weekend": { "base_price": 15000 } },
"units": [ { "name": "Room A", "external_id": "ROOM-A" }, { "name": "Room B", "external_id": "ROOM-B" } ]
}'
The 201 carries data.doorloom_id and every unit's
inventory_id next to the ids you sent. Store that mapping now; everything after this
point refers to properties and units by one id or the other. A portfolio goes in through
POST /properties/bulk,
25 at a time.
If the host already created the listing in the Doorloom app, do not create a copy. List what you cover:
curl https://doorloom.com/api/integrations/v1/properties \
-H "Authorization: Bearer $DOORLOOM_API_KEY"
Each property comes back with its doorloom_id, its external_id if
staff mapped one, and its units. Store those ids the same way. If a listing you expect is missing,
ask Doorloom to add it to your coverage.
A created property sends its own initial state
3. Receive and verify a webhook
Give Doorloom an HTTPS URL that answers POST. Then ask staff to send a test ping
to it, or make any calendar change in the Doorloom app to trigger a real event — creating a
property in step 2 already sent you several.
Your endpoint has exactly three obligations, and the first two matter more than they look:
- Verify the signature before trusting a byte of the payload.
- Answer 2xx within 10 seconds. Acknowledge first, process afterwards.
- Apply only if newer — the sequence rule, below.
# POST /hooks/doorloom
def webhook(request):
raw = request.get_data() # RAW bytes, not a re-encoded dict
header = request.headers.get("X-Doorloom-Signature", "")
if not verify(os.environ["DOORLOOM_WEBHOOK_SECRET"], raw, header):
return Response(status=401)
event = json.loads(raw)
# Hand off and return immediately. Anything slow happens off-request.
queue_for_processing(event)
return Response(status=204)
The verify() function is on the
signature page, in Python and
JavaScript. Copy it rather than writing your own — the two mistakes people make (hashing
re-serialised JSON, and accepting only the first v1=) both produce something that
works right up until it does not.
Do not process inside the request
4. Implement the sequence rule
Every event carries a sequence, and every payload is the full current
state for its scope, never a delta. So the entire correctness requirement is one line:
The rule
sequence is higher than
the last one you applied for that property and type. Otherwise ignore it.That makes duplicates, retries and out-of-order arrivals harmless without any other bookkeeping. Ordering and idempotency explains why it is sufficient.
5. Create a booking
curl -X POST https://doorloom.com/api/integrations/v1/bookings \
-H "Authorization: Bearer $DOORLOOM_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2f2a-6b3a-4a1e-9d2f-8a7c5e3b1d40" \
-d '{
"external_booking_id": "PMS-100234",
"property": { "external_id": "VILLA-9" },
"units": [ { "external_unit_id": "ROOM-A", "adults": 2, "children": 1, "meal_plan": "CP" } ],
"check_in": "2026-10-12",
"check_out": "2026-10-14",
"guest": { "name": "Asha Rao", "phone_code": "+91", "mobile": "9876543210" },
"pricing": { "total": 16000, "currency": "INR" },
"status": "confirmed"
}'
A 201 returns the booking. Two other outcomes are normal and neither is a bug:
200withdata.duplicate: true— you already created a booking with thisexternal_booking_id. Treat it as success.409 UNAVAILABLE— nothing was free for the whole stay.errors.availabilitycarries the per-night picture so you can correct your calendar in the same breath.
Send an Idempotency-Key on every create
6. Handle the echo
Moments later you will receive a booking.changed webhook for the booking you just
made, with origin: "partner". That is your own write coming back as confirmation.
You can ignore it, or use it to mark the write as durably landed. Property writes echo the same
way, as property.changed (and rates.changed or
inventory.changed when you touched those).
When the host edits that booking in the Doorloom app, you get the same event with
origin: "doorloom". That one you must apply.
Before you go live
- Signatures verified, bad ones rejected with a
401. - The sequence rule implemented per property and type, with your cursor persisted.
- 2xx inside 10 seconds; processing is asynchronous.
- Every property you sell mapped: created through the API or listed by
GET /properties, withdoorloom_idandinventory_idstored against your own ids. - On start-up and after any outage, call
GET /events?after_sequence=. If your cursor is older than 30 days, take snapshots instead. Idempotency-Keyon every create, booking or property;200 duplicateand409 PROPERTY_EXTERNAL_ID_EXISTSfor an id you already sent treated as "already done".409 UNAVAILABLEfeeds your calendar fromerrors.availability.- Money parsed as numbers, timestamps parsed with their offset.