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

Bulk create and update

Load or change up to 25 properties in one call. The whole batch is validated before anything is written; then each property is created or updated on its own, and the response tells you, item by item, what happened.

POST https://doorloom.com/api/integrations/v1/properties/bulk Idempotency-Key required
PUT https://doorloom.com/api/integrations/v1/properties/bulk

Headers

Field Type Required Description
Authorization string Required Bearer <your API key>.
Content-Type string Required application/json.
Idempotency-Key string POST only 8 to 128 characters, unique per batch attempt. The whole batch response is stored against it.

Request body

Body

Field Type Required Description
properties array Required 1 to 25 entries.
properties[] object Required On POST: a create body. On PUT: an update body plus the reference below.
properties[].doorloom_id integer PUT, one of the two Which property this entry changes.
properties[].external_id string PUT, one of the two Which property this entry changes, by your id. In a bulk update this field only identifies the property; it never re-maps it. Use the single PUT /properties/{id} for that.

How a batch is processed

  1. The whole payload is validated first. A structural error anywhere — a missing name in item 7, a duplicated external_id between items 2 and 9 — fails the request with 422 VALIDATION_FAILED and nothing is written. The errors keys are prefixed with the item index: properties.7.name.
  2. Then each item runs on its own, in order, in its own transaction. A refusal that can only be known at write time — an external_id already mapped, a property no longer in your coverage — fails that item and that item alone. The others go through.
  3. The response reports every item, successes and failures, with a summary.
Request (bulk create) bash
curl -X POST https://doorloom.com/api/integrations/v1/properties/bulk \
  -H "Authorization: Bearer $DOORLOOM_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9a7e2d0c-5b41-4f6e-8c3d-1e2f3a4b5c6d" \
  -d '{
    "properties": [
      { "external_id": "VILLA-001", "name": "Amber Villa", "description": "…", "address": { "…": "…" }, "space": { "bedrooms": 3, "washrooms": 3 }, "occupancy": { "max_guests": 8 }, "pricing": { "weekday": { "base_price": 12000 }, "weekend": { "base_price": 15000 } } },
      { "external_id": "VILLA-002", "name": "Coral Villa", "description": "…", "address": { "…": "…" }, "space": { "bedrooms": 2, "washrooms": 2 }, "occupancy": { "max_guests": 6 }, "pricing": { "weekday": { "base_price": 9000 }, "weekend": { "base_price": 11000 } } }
    ]
  }'

Response

Field Type Description
201 all created Bulk create, every item succeeded.
200 completed Bulk update (always), or a bulk create in which at least one item failed. success is still true: the request was processed. Read data.summary and data.results[].
422 nothing written The payload failed validation as a whole.
Response 200 (one item failed) json
{
    "success": true,
    "message": "Some properties were not created",
    "data": {
        "summary": {
            "requested": 2,
            "succeeded": 1,
            "failed": 1
        },
        "results": [
            {
                "index": 0,
                "external_id": "VILLA-001",
                "status": "created",
                "property": {
                    "doorloom_id": 902,
                    "external_id": "VILLA-001",
                    "coverage": "active",
                    "name": "Amber Villa",
                    "…": "…"
                }
            },
            {
                "index": 1,
                "external_id": "VILLA-002",
                "status": "failed",
                "error": {
                    "code": "PROPERTY_EXTERNAL_ID_EXISTS",
                    "message": "A property with this external_id already exists for your integration.",
                    "errors": {
                        "external_id": "VILLA-002",
                        "doorloom_id": 877
                    }
                }
            }
        ]
    }
}

Response fields

Field Type Description
summary.requested integer Items in the batch.
summary.succeeded integer Items created (or updated).
summary.failed integer Items refused.
results[].index integer Position in your properties[], from 0.
results[].external_id string|null On a create: the id you sent for that item.
results[].doorloom_id integer|null On an update: the property the entry resolved to.
results[].status string created, updated or failed.
results[].property object On success: the property block, as GET /properties returns it.
results[].error object On failure: code, message and, where the single endpoint would carry one, errors — the same shapes as the single-endpoint responses.

Idempotency and retries

A bulk create is stored against its Idempotency-Key as a whole: resending the identical batch under the same key replays the identical response, including the items that failed, and creates nothing. To retry only the failed items after fixing them, send a new batch containing just those items under a new key — the items that succeeded would otherwise be refused with PROPERTY_EXTERNAL_ID_EXISTS, which is the safety net if you resend everything by mistake.

A bulk update needs no key: each item is idempotent for the same reasons the single PUT is.

Limits

  • 25 items per batch, 50 units per item.
  • The bulk tier is 6 calls a minute, so a portfolio of 150 properties loads in one minute; see rate limits.
  • Each created property sends its initial snapshot — around forty events — through your webhook, in sequence order. A batch of 25 queues roughly a thousand deliveries; expect them to drain over some minutes rather than instantly.

Errors

Request-level (nothing written):

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.
422 IDEMPOTENCY_KEY_REQUIRED A create — POST /bookings, POST /properties or POST /properties/bulk — was sent without a usable Idempotency-Key header.
422 IDEMPOTENCY_KEY_REUSED The key has already been used, with a different request body. Doorloom fingerprints the body (SHA-256 over key-sorted JSON), so key order does not matter but any value change does. Keys are shared across every create endpoint, so a booking key resent on a property create is a reuse too.
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.

Item-level (inside results[].error): PROPERTY_EXTERNAL_ID_EXISTS, NOT_FOUND, PROPERTY_ARCHIVED and VALIDATION_FAILED for unit rules — with the meanings on the single-endpoint pages.

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.