Developers

Lazybee Partner API

Programmatic access to Lazybee co-living inventory: properties, room listings with media and features, live availability calendars, partner rates, booking-request intake and signed webhooks. JSON over HTTPS, versioned as v1, dates in ISO 8601, amounts in SGD.

Base URL and authentication

All endpoints live under https://www.lazybee.sg/api/v1 (the bare domain redirects here; use the www host in scripts so plain curl works without following redirects). Every request carries your API key in the Authorization header. Keys are issued per partner and can be revoked or rate-limited independently.

curl -s https://www.lazybee.sg/api/v1/ping \
  -H "Authorization: Bearer $LAZYBEE_API_KEY"

{"ok":true,"partner":"Your Platform","version":"v1"}

Properties

GET /properties lists our buildings. GET /properties/{slug} returns one.

{
  "slug": "ivory-heights",
  "profile": { "title": "Ivory Heights", "description": "..." },
  "media": [ { "url": "https://...jpg", "hero": true } ],
  "features": [ "pool", "gym", "near-mrt" ],
  "listing_count": 7,
  "links": {
    "canonical": "https://lazybee.sg/properties/ivory-heights",
    "book": "https://book.lazybee.sg"
  },
  "updated_at": "2026-08-01T02:11:09Z"
}

Listings

GET /listings returns every lettable room. Filter with property, available_from and max_rate. Rates are quoted per month for a default 12-month stay; pass duration_months (3 to 36) to quote a different length. GET /listings/{code} returns one room.

{
  "code": "IH-STD1",
  "property": "ivory-heights",
  "profile": { "title": "Standard Room 1", "description": "..." },
  "media": [ { "url": "https://...jpg", "hero": true } ],
  "features": [ "aircon", "window" ],
  "rate_card": {
    "monthly_rate": 1500,
    "deposit": 1500,
    "min_stay_months": 3,
    "currency": "SGD",
    "duration_months": 12
  },
  "available_from": "2026-09-01",
  "max_occupancy": 2,
  "links": {
    "canonical": "https://lazybee.sg/rooms/IH-STD1",
    "book": "https://book.lazybee.sg"
  },
  "updated_at": "2026-08-05T11:40:00Z"
}

Availability calendar

GET /listings/{code}/calendar returns date windows one year ahead. A window is open or unavailable and carries nothing else: no occupant information, by design.

{
  "listing": "IH-STD1",
  "from": "2026-08-12",
  "horizon_days": 365,
  "windows": [
    { "start": "2026-08-12", "end": "2026-08-31", "status": "open" },
    { "start": "2026-09-01", "end": "2026-12-14", "status": "unavailable" },
    { "start": "2026-12-15", "end": "2027-08-12", "status": "open" }
  ]
}

Booking requests

Push a tenant to us with POST /booking-requests. Include an idempotency_key so safe retries never create duplicates. Status moves through received, in_review, then confirmed or declined; poll GET /booking-requests/{id} or subscribe to the booking_request.updated webhook.

curl -s -X POST https://www.lazybee.sg/api/v1/booking-requests \
  -H "Authorization: Bearer $LAZYBEE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "listing_code": "IH-STD1",
    "move_in": "2026-10-01",
    "duration_months": 6,
    "idempotency_key": "your-ref-123",
    "applicant": { "name": "Jane Tan", "email": "jane@example.com", "phone": "+65..." }
  }'

{"id":"1f4c...","listing_code":"IH-STD1","status":"received","created_at":"..."}

Bookings

Where a booking request is a lead we review, POST /bookings places a confirmed hold that immediately blocks the calendar. Provide starts_on and optionally ends_on (omit for open-ended), your own external_ref, and an idempotency_key for safe retries. Manage with GET /bookings, GET /bookings/{id} and POST /bookings/{id}/cancel. Every create and status change emits the booking.updated webhook to you.

curl -s -X POST https://www.lazybee.sg/api/v1/bookings \
  -H "Authorization: Bearer $LAZYBEE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "listing_code": "IH-STD1",
    "starts_on": "2026-10-01",
    "ends_on": "2027-03-31",
    "external_ref": "your-booking-8891",
    "idempotency_key": "your-booking-8891",
    "guest": { "name": "Jane Tan", "email": "jane@example.com" }
  }'

{"id":"...","listing_code":"IH-STD1","starts_on":"2026-10-01","ends_on":"2027-03-31",
 "status":"confirmed","external_ref":"your-booking-8891","created_at":"..."}

Webhooks

Register an HTTPS endpoint with POST /webhooks and choose from five events: listing.calendar.updated, listing.rates.updated, listing.profile.updated, booking_request.updated and booking.updated. The response includes your signing secret, shown once. Payloads are pointers; re-read the API for current state. Deliveries retry with backoff for up to eight attempts.

// Verify the Lazybee-Signature header (t=<unix>,v1=<hmac>)
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, body, header) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? "");
  if (!m) return false;
  const mac = createHmac("sha256", secret).update(m[1] + "." + body).digest("hex");
  return timingSafeEqual(Buffer.from(mac, "hex"), Buffer.from(m[2], "hex"));
}

Rate limits and errors

Default limit is 60 requests per minute per key; excess returns HTTP 429. Errors always use one envelope:

{ "error": { "code": "validation_failed", "message": "Missing: move_in" } }

Request access

Keys are issued directly by our team. Write to mark@lazybee.sg with your platform name and what you plan to build, and we will set you up with a key and, where relevant, your contracted rate card.