How to build: guest — search and book
Browse and detail read Core with the public site API key (it will be in the browser). Availability is Middleware. Do not invent the final check only in the browser.
Guests search properties (hotel, shortlet, or apartment). Apartment-by-unit uses room + rate plan like a hotel; whole apartment uses the shortlet booking parent.
Search properties → Property detail + rate plans → Check availability → Select plan → Checkout1. List active properties
Core · winner
GET https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/property?status=active&per_page=20&page=1&sort_by=title_name&sort_order=asc
x-api-key: {API_KEY}Use the public browse key. No Bearer required for active listings. Core path settings must allow only those GETs on this key — not booking or payment. See Security and IDOR.
Filter by type (hotel, shortlet, or apartment)
GET .../entity/property?search=hotel&search_by=meta_key.property_category&status=active
Filter by city
GET .../entity/property?search=Lagos&search_by=meta_key.city&status=active
Filter by amenity
GET .../entity/property?search=true&search_by=meta_key.amenity_swimming_pool&status=active
AND across many amenities: one query each, intersect in the UI — or fetch a page and filter client-side. Core has no multi-amenity AND in one call (limitations).
Search by name
GET .../entity/property?search=ABC&search_by=title_name&status=active
2. Property detail
Core · winner
GET https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/property/{property_uuid}
Then children:
GET .../entity/room?parent_entity_type=property&parent_entity_uuid={property_uuid}&status=active
GET .../entity/rate_plan?parent_entity_type=room&parent_entity_uuid={room_uuid}&status=activeRender title, meta_data (address, times), amenities (amenity_* or extra_data.amenities), and each plan’s base_rate_ngn.
Get by slug if the route is /hotel/abc-hotel-lagos:
GET https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/property/slug/abc-hotel-lagos
3. Check availability (do not skip)
Middleware · winner · to implement
POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/availability/check
Contract: specs/middleware/v1/openapi.yaml
Authorization: Bearer {access_token}
Content-Type: application/json{
"property_uuid": "{property_uuid}",
"check_in": "2026-10-01",
"check_out": "2026-10-03",
"units_needed": 1
}Middleware reads Core rooms, rate plans, and overlapping bookings, then returns remaining units per plan. Algorithm (for Middleware implementers): Availability.
Show only plans where available >= units_needed. Dates stay in frontend state — Core has no date query param.
How to build: show plans where available >= units_needed. Middleware must return counts only (no guest PII). That is a Middleware IDOR/privacy rule, not a Vue task.
4. Guest login (if not already)
Same winners as Sign up and login:
POST https://backend-dev.bookdirect.live/public/api/v1/nellalink/user/registerPOST https://backend-dev.bookdirect.live/public/api/v1/nellalink/user/login
Guests need a Core user so owned_by on the booking is their uuid.
5. Create booking (pending)
Happens on the checkout screen. Winner is Core. Full body and payment: Checkout and pay.
Core · winner
POST https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/booking
Hotel: parent_entity_type = rate_plan. Shortlet: parent_entity_type = property. Always put property_uuid inside extra_data. Status starts as pending.
Re-run availability immediately before POST. If Middleware says not enough units, do not submit.
Guest checklist
- [ ] Search uses Core list + meta filters
- [ ] Detail loads property + rooms + rate plans
- [ ] Dates + occupancy live in UI state
- [ ] Availability goes through Middleware, not a local-only guess as the final check
- [ ] Guest is logged in before create booking
- [ ] Unique
request_idper booking submit