How to build: owner — set up a property
Winner: Core for property / room / rate_plan / metadata. Middleware only for image upload and (later) Google push.
Hotels, shortlets, and apartments use the same create-property URL. Set property_category in the next step (hotel | shortlet | apartment). Apartment sold by unit → rooms + rate plans. Apartment sold as a whole → shortlet pattern.
Login → Create property (draft) → Metadata + amenities → Rooms → Rate plans → Upload photos → Publish (status: active)Entity types and extra_data keys: Entities and Metadata catalog.
1. Create property
Core · winner
Call this API
POST https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/property
Path: POST /public/api/v1/nellalink/smart-meta-manager/entity/property
Explorer: Core — Smart Meta Manager
Headers
x-api-key: {API_KEY}
Authorization: Bearer {access_token}
Content-Type: application/jsonRequest
{
"request_id": "prop-abc-hotel-001",
"meta_key": "abc_hotel_lagos",
"slug": "abc-hotel-lagos",
"title_name": "ABC Hotel Lagos",
"description": "A 10-room boutique hotel in Victoria Island.",
"owned_by": "{session_user_uuid}",
"status": "draft",
"extra_data": {
"gallery_urls": [],
"total_rooms_display": 10
},
"categories": [{ "name": "Hotel" }],
"tags": ["hotel"]
}owned_by must be the logged-in user’s uuid. request_id must be unique (use it to ignore double-clicks).
Save from response: data.uuid → {property_uuid}.
For a shortlet or apartment, use the same endpoint; set property_category to shortlet or apartment in the next step.
How to build: send owned_by = session uuid. Core must reject a JWT mismatch (require_user_bearer_token + owner check on this POST path). If that is missing, recommend it on Core path settings — not as a Vue IDOR task.
If Middleware later owns “upload property”
A future POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/properties would become the winner. This Core URL would move to “Called by Middleware, not by frontend.” Propose that on /next — do not change v1 until that route is live.
2. Add location and details (metadata)
Core · winner
Call this API
POST https://backend-dev.bookdirect.live/public/api/v1/nellalink/meta-data/entity/property/{property_uuid}
Send an array for several keys:
[
{ "meta_key": "property_category", "meta_value": "hotel", "data_type": "string" },
{ "meta_key": "address", "meta_value": "12 Admiralty Way, Victoria Island", "data_type": "string" },
{ "meta_key": "city", "meta_value": "Lagos", "data_type": "string" },
{ "meta_key": "state", "meta_value": "Lagos", "data_type": "string" },
{ "meta_key": "country", "meta_value": "Nigeria", "data_type": "string" },
{ "meta_key": "latitude", "meta_value": "6.4281", "data_type": "string" },
{ "meta_key": "longitude", "meta_value": "3.4219", "data_type": "string" },
{ "meta_key": "check_in_time", "meta_value": "14:00", "data_type": "string" },
{ "meta_key": "check_out_time", "meta_value": "11:00", "data_type": "string" }
]Shortlet: "meta_value": "shortlet". Apartment: "meta_value": "apartment". Hotel: "hotel".
3. Amenities (tick boxes)
Same metadata endpoint. One row per ticked amenity. Full table: Metadata catalog.
[
{ "meta_key": "amenity_swimming_pool", "meta_value": "true", "data_type": "boolean" },
{ "meta_key": "amenity_free_parking", "meta_value": "true", "data_type": "boolean" }
]To untick: PUT the same key with "meta_value": "false".
Optional mirror on the property for easy UI read:
Core · winner
PUT https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/property/{property_uuid}
extra_data replaces the whole object. Always send the full object.
4. Create a room (hotel)
Core · winner
Call this API
POST https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/room
{
"request_id": "room-abc-standard-001",
"meta_key": "standard_room",
"slug": "standard-room",
"title_name": "Standard Room",
"description": "Queen bed, city view.",
"parent_entity_type": "property",
"parent_entity_uuid": "{property_uuid}",
"owned_by": "{session_user_uuid}",
"status": "active",
"extra_data": {
"total_units": 3,
"room_numbers": ["RM1", "RM2", "RM3"],
"max_occupancy": 2,
"bed_type": "queen"
}
}Save data.uuid → {room_uuid}. Repeat per room type (Deluxe, VIP).
The old desktop guide’s booking_package is this room plus a rate_plan.
5. Create a rate plan
Core · winner
Call this API
POST https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/rate_plan
{
"request_id": "rp-abc-standard-flex-001",
"meta_key": "standard_flexible",
"slug": "standard-flexible",
"title_name": "Flexible rate",
"parent_entity_type": "room",
"parent_entity_uuid": "{room_uuid}",
"owned_by": "{session_user_uuid}",
"status": "active",
"extra_data": {
"base_rate_ngn": 30000,
"currency": "NGN",
"cancellation": "free_24h",
"breakfast_included": false
}
}Save {rate_plan_uuid}. Google ARI later keys off room + rate_plan.
6. Upload photos (Middleware)
Middleware · winner
Call this API
POST https://middleware-dev.bookdirect.live/api/v1/nellalink/file-manager/aws/upload-url
Already live. Explorer: Middleware docs
Authorization: Bearer {access_token}
Content-Type: application/json{
"files": [
{ "file_name": "cover.jpg", "file_type": "image/jpeg", "file_size": 240000, "visibility": "public" }
]
}PUT the file bytes to the returned URL, then PUT the property entity_featured_url / extra_data.gallery_urls on Core.
7. Publish
Core · winner
PUT https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/property/{property_uuid}
{ "status": "active" }After publish, owner tools may call Google rates push (Middleware). Frontend does not talk to GuestTraction directly.
8. List my properties
Core · winner
GET https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/property?owned_by={session_user_uuid}&per_page=20&page=1
How to build the dashboard list: pass owned_by={session_user_uuid} so the UI shows the owner’s rows. Core must still scope the write key + JWT so a public browse key cannot list another owner’s drafts or all bookings.
Rooms for a property:
GET .../entity/room?parent_entity_type=property&parent_entity_uuid={property_uuid}&per_page=50
Rate plans for a room:
GET .../entity/rate_plan?parent_entity_type=room&parent_entity_uuid={room_uuid}
Shortlet or whole apartment (no rooms)
- Create
propertyas above. - Metadata
property_category=shortletorapartment. - Put inventory and price on the property
extra_data:
{
"total_units": 1,
"base_rate_ngn": 150000,
"currency": "NGN",
"max_occupancy": 6
}Bookings use parent_entity_type: "property". See Guest search and book.
Owner checklist
- [ ] Login → token + uuid
- [ ] POST property (
draft) - [ ] POST metadata (location, category, times)
- [ ] POST amenity metadata
- [ ] POST each room + rate_plan (hotel / apartment-by-unit) or extra_data rates (shortlet / whole apartment)
- [ ] Upload images via Middleware file-manager
- [ ] PUT property
status: active - [ ] GET property + children to verify