# Trisolaris Server API Manual (Manual, No Script) Last updated: 2026-02-04 Source: current Kotlin controllers in this repo. ## Global rules - Base API domain: `api.hoteltrisolaris.in` - Auth: Firebase bearer token (`MyPrincipal`) for all non-public endpoints. - Super admin bypass: property membership/role checks are bypassed by `superAdmin=true` (via `PropertyAccess`). - Global API error shape: ```json { "timestamp": "...", "status": 400, "error": "Bad Request", "message": "...", "path": "/..." } ``` - Common auth/permission errors: - `401 Unauthorized`: missing principal / user not found - `403 Forbidden`: missing membership/role ## Public endpoints (no auth required) - `GET /` - `GET /health` - `GET /auth/*` - `GET /properties/{propertyId}/rooms/available` - `GET /properties/{propertyId}/rooms/by-type/{roomTypeCode}` - `GET /properties/{propertyId}/room-types` - `GET /properties/{propertyId}/room-types/{roomTypeCode}/images` - `GET /properties/{propertyId}/rooms/{roomId}/images` - `GET /properties/{propertyId}/rooms/{roomId}/images/{imageId}/file` - `GET /properties/{propertyId}/guests/{guestId}/documents/{documentId}/file` (or token-based access) - `GET /properties/{propertyId}/cancellation-policy` - `GET /image-tags` - `GET /icons/png` - `GET /icons/png/{filename}` - `POST /properties/{propertyId}/razorpay/webhook` - `POST /properties/{propertyId}/razorpay/return/success` - `POST /properties/{propertyId}/razorpay/return/failure` ## Core storage map - Property + config: `property`, `property_email_address`, `property_email_alias`, `property_transport_mode` - Users + membership: `app_user`, `property_user`, `property_user_role`, `property_access_code`, `property_access_code_role` - Room inventory: `room_type`, `room_type_alias`, `room_type_amenity_link`, `room`, `room_amenity` - Stays + cards: `room_stay`, `room_stay_audit_log`, `issued_card`, `property_card_counter` - Booking + billing: `booking`, `booking_room_request`, `booking_billing_policy_audit_log`, `charge`, `payment` - Guest data: `guest`, `guest_vehicle`, `guest_rating`, `guest_document` - Rates: `rate_plan`, `rate_calendar` - Email ingest: `inbound_email` - Room media: `room_image`, `room_image_tag`, `room_image_tag_link` - Razorpay: `razorpay_settings`, `razorpay_qr_request`, `razorpay_payment_link_request`, `razorpay_payment_attempt`, `razorpay_webhook_log` - File storage roots: - documents/signatures: `/home/androidlover5842/docs` - emails: `/home/androidlover5842/docs/emails` - room images: `/home/androidlover5842/docs/rooms` - icons: `/home/androidlover5842/docs/icons/png` --- ## 1) Auth APIs - `POST /auth/verify` - What it does: resolves Firebase principal (creates app user if missing), returns user + property memberships. - Access: public. - Stores data: may insert/update `app_user`; reads `property_user`. - `GET /auth/me` - What it does: same shape as verify. - Access: public. - Stores data: may create `app_user` if resolver is used. - `PUT /auth/me` - Request: `{ "name": "..." }` - What it does: updates current user name. - Access: authenticated user. - Stores data: updates `app_user.name`. ## 2) System + Static assets - `GET /health` / `GET /` - What it does: health payload with build identifier. - Access: public. - Stores data: none. - `GET /icons/png` - What it does: lists PNG filenames in icon root. - Access: public. - Stores data: reads filesystem only. - `GET /icons/png/{filename}` - What it does: serves icon PNG. - Access: public. - Stores data: reads filesystem only. ## 3) Property + User management - `POST /properties` - Request: `PropertyCreateRequest`. - Access: authenticated user. - Stores data: inserts `property` (+ email/alias/transport collections); inserts `property_user` with `ADMIN`. - `GET /properties` - What it does: list properties (all for super admin, memberships for others). - Access: authenticated user. - Stores data: reads `property`, `property_user`. - `GET /properties/{propertyId}/code` - Access: property member. - Stores data: reads `property.code`. - `PUT /properties/{propertyId}` - Request: `PropertyUpdateRequest`. - Access: `ADMIN`. - Stores data: updates `property` and its collection tables. - `GET /properties/{propertyId}/billing-policy` - Access: property member. - Stores data: reads `property.billing_checkin_time`, `property.billing_checkout_time`. - `PUT /properties/{propertyId}/billing-policy` - Request: `PropertyBillingPolicyRequest`. - Access: `ADMIN`. - Stores data: updates `property` billing policy. - `GET /properties/{propertyId}/users` - Access: `ADMIN`/`MANAGER`. - Stores data: reads `property_user`, `app_user`. - `PUT /properties/{propertyId}/users/{userId}/roles` - Request: `PropertyUserRoleRequest`. - Access: super admin / `ADMIN` / `MANAGER` (role-limited by hierarchy). - Stores data: upserts `property_user` + `property_user_role`. - `PUT /properties/{propertyId}/users/{userId}/disabled` - Request: `PropertyUserDisableRequest`. - Access: hierarchy-based. - Stores data: updates `property_user.is_disabled`. - `DELETE /properties/{propertyId}/users/{userId}` - Access: `ADMIN`. - Stores data: deletes `property_user` membership. ### Access codes + directory - `POST /properties/{propertyId}/access-codes` - Request: `PropertyAccessCodeCreateRequest` (`roles`, no `ADMIN`). - Access: `ADMIN`. - Stores data: inserts `property_access_code` + `property_access_code_role` (1-minute expiry). - `POST /properties/access-codes/join` - Request: `PropertyAccessCodeJoinRequest` (`propertyCode` + `code`). - Access: authenticated. - Stores data: inserts `property_user`; marks `property_access_code.used_at/used_by`. - `GET /users` - Query: optional `phone`. - Access: super admin only. - Stores data: reads `app_user`. - `GET /properties/{propertyId}/users/search` - Query: optional `phone`. - Access: `ADMIN`. - Stores data: reads `property_user`, `app_user`. ### Cancellation policy + transport modes - `GET /properties/{propertyId}/cancellation-policy` - Access: public. - Stores data: reads `property_cancellation_policy` (or default response). - `PUT /properties/{propertyId}/cancellation-policy` - Request: `CancellationPolicyUpsertRequest`. - Access: `ADMIN`. - Stores data: upserts `property_cancellation_policy`. - `GET /properties/{propertyId}/transport-modes` - Access: property member. - Stores data: reads `property.allowedTransportModes`. ## 4) Room amenities + image tags - `GET /amenities` - Access: authenticated. - Stores data: reads `room_amenity`. - `POST /amenities` - Request: `AmenityUpsertRequest`. - Access: super admin only. - Stores data: inserts `room_amenity`. - `PUT /amenities/{amenityId}` - Request: `AmenityUpsertRequest`. - Access: super admin only. - Stores data: updates `room_amenity`. - `DELETE /amenities/{amenityId}` - Access: super admin only. - Stores data: deletes `room_amenity`; removes links from `room_type_amenity_link`. - `GET /image-tags` - Access: public. - Stores data: reads `room_image_tag`. - `POST /image-tags` - Request: `RoomImageTagUpsertRequest`. - Access: super admin only. - Stores data: inserts `room_image_tag`. - `PUT /image-tags/{tagId}` - Request: `RoomImageTagUpsertRequest`. - Access: super admin only. - Stores data: updates `room_image_tag`. - `DELETE /image-tags/{tagId}` - Access: super admin only. - Stores data: deletes links from `room_image_tag_link`, deletes `room_image_tag`. ## 5) Room types - `GET /properties/{propertyId}/room-types` - Access: public (or member when auth present). - Stores data: reads `room_type` + alias/amenity links. - `POST /properties/{propertyId}/room-types` - Request: `RoomTypeUpsertRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: inserts `room_type`, `room_type_alias`, `room_type_amenity_link`. - `PUT /properties/{propertyId}/room-types/{roomTypeId}` - Request: `RoomTypeUpsertRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: updates `room_type` and links. - `DELETE /properties/{propertyId}/room-types/{roomTypeId}` - Access: `ADMIN`/`MANAGER`. - Stores data: soft delete by setting `room_type.is_active=false`. - `GET /properties/{propertyId}/room-types/{roomTypeCode}/rate?date=...&ratePlanCode=...` - Access: public/member. - Stores data: reads `room_type`, `rate_plan`, `rate_calendar`. ## 6) Rooms + availability + board - `GET /properties/{propertyId}/rooms` - Access: property member (agents see only free sellable rooms). - Stores data: reads `room`, active stays in `room_stay`, temp cards in `issued_card`. - `POST /properties/{propertyId}/rooms` - Request: `RoomUpsertRequest`. - Access: `ADMIN`. - Stores data: inserts `room`. - `PUT /properties/{propertyId}/rooms/{roomId}` - Request: `RoomUpsertRequest`. - Access: `ADMIN`. - Stores data: updates `room`. - `DELETE /properties/{propertyId}/rooms/{roomId}` - Access: `ADMIN`/`MANAGER`. - Stores data: deletes room image files + `room_image` rows, then deletes `room` (blocked if any `room_stay` exists). - `GET /properties/{propertyId}/rooms/board` - Access: member (agent filtered to FREE). - Stores data: reads `room`, active occupancy from `room_stay`. - `GET /properties/{propertyId}/rooms/board/stream` - Access: member. - Stores data: no writes; SSE from derived room board events. - `GET /properties/{propertyId}/rooms/availability` - Access: member. - Stores data: reads `room`, `room_stay`. - `GET /properties/{propertyId}/rooms/available` - Access: public. - Stores data: reads `room`, `room_stay`, `issued_card`. - `GET /properties/{propertyId}/rooms/by-type/{roomTypeCode}?availableOnly=true|false` - Access: public. - Stores data: reads `room_type`, `room`, `room_stay`, `issued_card`. - `GET /properties/{propertyId}/rooms/availability-range?from=YYYY-MM-DD&to=YYYY-MM-DD` - Access: member. - Stores data: reads `room`, `room_stay`, `property.timezone`. - `GET /properties/{propertyId}/rooms/available-range-with-rate?from=...&to=...&ratePlanCode=...` - Access: member. - Stores data: reads `room`, `room_stay`, `rate_plan`, `rate_calendar`, `property`. ## 7) Room images - `GET /properties/{propertyId}/rooms/{roomId}/images` - Access: public. - Stores data: reads `room_image`; deletes missing-file rows; reads filesystem. - `POST /properties/{propertyId}/rooms/{roomId}/images` - Multipart: file + optional `tagIds`. - Access: `ADMIN`/`MANAGER`. - Stores data: writes files under `/docs/rooms`; inserts `room_image` + `room_image_tag_link`. - `DELETE /properties/{propertyId}/rooms/{roomId}/images/{imageId}` - Access: `ADMIN`/`MANAGER`. - Stores data: deletes files + `room_image`; reorders sort fields. - `PUT /properties/{propertyId}/rooms/{roomId}/images/{imageId}/tags` - Request: `RoomImageTagUpdateRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: updates `room_image_tag_link`. - `PUT /properties/{propertyId}/rooms/{roomId}/images/reorder-room` - Request: `RoomImageReorderRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: updates `room_image.sort_order`. - `PUT /properties/{propertyId}/rooms/{roomId}/images/reorder-room-type` - Request: `RoomImageReorderRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: updates `room_image.room_type_sort_order`. - `GET /properties/{propertyId}/rooms/{roomId}/images/{imageId}/file?size=full|thumb` - Access: public/member. - Stores data: reads filesystem + `room_image` metadata. - `GET /properties/{propertyId}/room-types/{roomTypeCode}/images` - Access: public. - Stores data: reads `room_image`; prunes missing-file rows. ## 8) Room stays + cards - `GET /properties/{propertyId}/room-stays/active` - Access: member except AGENT-only users. - Stores data: reads `room_stay`, `booking`, `guest`, `room`. - `POST /properties/{propertyId}/room-stays/{roomStayId}/void` - Request: `RoomStayVoidRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF` (staff blocked after first booking payment). - Stores data: updates `room_stay` (`is_voided`, `to_at`), inserts `room_stay_audit_log`, may update `booking` to `CHECKED_OUT`. ### Issued cards (room stay) - `POST /properties/{propertyId}/room-stays/{roomStayId}/cards/prepare` - Request: `CardPrepareRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: increments `property_card_counter`; returns encoded payload only. - `POST /properties/{propertyId}/room-stays/{roomStayId}/cards` - Request: `IssueCardRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: inserts `issued_card`. - `GET /properties/{propertyId}/room-stays/{roomStayId}/cards` - Access: `STAFF`/`ADMIN`/`MANAGER`/`SUPERVISOR`. - Stores data: reads `issued_card`. - `POST /properties/{propertyId}/room-stays/cards/{cardIndex}/revoke` - Access: ADMIN for regular cards; ADMIN/MANAGER for temp cards. - Stores data: updates `issued_card.revoked_at` and `expires_at`. - `GET /properties/{propertyId}/room-stays/cards/{cardIndex}` - Access: `ADMIN`/`MANAGER`. - Stores data: reads `issued_card`. ### Temporary room cards - `POST /properties/{propertyId}/rooms/{roomId}/cards/prepare-temp` - Access: `ADMIN`/`MANAGER`. - Stores data: increments `property_card_counter`; returns payload only. - `POST /properties/{propertyId}/rooms/{roomId}/cards/temp` - Request: `IssueTempCardRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: inserts temp `issued_card` (7-minute expiry). ## 9) Booking APIs - `POST /properties/{propertyId}/bookings` - Request: `BookingCreateRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: inserts `booking`; creates placeholder `guest` if needed. - `GET /properties/{propertyId}/bookings?status=...` - Access: `ADMIN`/`MANAGER`/`STAFF`/`HOUSEKEEPING`/`FINANCE`. - Stores data: reads `booking`, `room_stay`, `charge`, `payment`. - `GET /properties/{propertyId}/bookings/{bookingId}` - Access: same as list. - Stores data: reads booking snapshot from `booking`, `guest`, `room_stay`, `guest_vehicle`, `charge`, `payment`. - `GET /properties/{propertyId}/bookings/{bookingId}/stream` - Access: same as list. - Stores data: no writes; SSE booking event stream. - `POST /properties/{propertyId}/bookings/{bookingId}/link-guest` - Request: `BookingLinkGuestRequest`. - Access: property member. - Stores data: updates `booking.primary_guest_id`; may delete placeholder `guest` when safe. - `POST /properties/{propertyId}/bookings/{bookingId}/check-in/bulk` - Request: `BookingBulkCheckInRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: inserts `room_stay`; updates `booking` to `CHECKED_IN`; may fulfill `booking_room_request`. - `POST /properties/{propertyId}/bookings/{bookingId}/expected-dates` - Request: `BookingExpectedDatesUpdateRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: updates `booking.expected_checkin_at` / `booking.expected_checkout_at`. - `POST /properties/{propertyId}/bookings/{bookingId}/billing-policy` - Request: `BookingBillingPolicyUpdateRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: updates `booking.billing_*`; inserts `booking_billing_policy_audit_log` when changed. - `POST /properties/{propertyId}/bookings/{bookingId}/check-out` - Request: `BookingCheckOutRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: closes active `room_stay` rows (`to_at`), inserts `room_stay_audit_log`, updates `booking` to `CHECKED_OUT`. - `POST /properties/{propertyId}/bookings/{bookingId}/room-stays/{roomStayId}/check-out` - Request: `BookingCheckOutRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: closes specific `room_stay`, inserts audit log, may auto-close `booking`. - `POST /properties/{propertyId}/bookings/{bookingId}/cancel` - Request: `BookingCancelRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: updates `booking.status=CANCELLED`; may insert penalty row in `charge`. - `POST /properties/{propertyId}/bookings/{bookingId}/no-show` - Request: `BookingNoShowRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: updates `booking.status=NO_SHOW`; may insert penalty row in `charge`. ### Room requests + booking balance - `POST /properties/{propertyId}/bookings/{bookingId}/room-requests` - Request: `BookingRoomRequestCreateRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: inserts `booking_room_request`. - `GET /properties/{propertyId}/bookings/{bookingId}/room-requests` - Access: `ADMIN`/`MANAGER`/`STAFF`/`HOUSEKEEPING`/`FINANCE`. - Stores data: reads `booking_room_request`. - `DELETE /properties/{propertyId}/bookings/{bookingId}/room-requests/{requestId}` - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: sets `booking_room_request.status=CANCELLED`. - `GET /properties/{propertyId}/bookings/{bookingId}/balance` - Access: property member. - Stores data: reads `room_stay`, `charge`, `payment` and returns computed ledger balance. ## 10) Charges + Payments APIs - `POST /properties/{propertyId}/bookings/{bookingId}/charges` - Request: `ChargeCreateRequest`. - Access: `ADMIN`/`MANAGER`/`FINANCE`. - Stores data: inserts `charge`. - `GET /properties/{propertyId}/bookings/{bookingId}/charges` - Access: property member. - Stores data: reads `charge`. - `POST /properties/{propertyId}/bookings/{bookingId}/payments` - Request: `PaymentCreateRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: inserts `payment`. - `GET /properties/{propertyId}/bookings/{bookingId}/payments` - Access: property member. - Stores data: reads `payment`. - `DELETE /properties/{propertyId}/bookings/{bookingId}/payments/{paymentId}` - Access: `ADMIN` (super admin allowed through bypass). - Stores data: deletes `payment` only when method is CASH and booking is OPEN/CHECKED_IN. ## 11) Guest APIs - `PUT /properties/{propertyId}/guests/{guestId}` - Request: `GuestUpdateRequest`. - Access: property member. - Stores data: updates `guest`. - `GET /properties/{propertyId}/guests/search?phone=...|vehicleNumber=...` - Access: property member. - Stores data: reads `guest`, `guest_vehicle`, `guest_rating`. - `GET /properties/{propertyId}/guests/{guestId}` - Access: property member. - Stores data: reads `guest`, `guest_vehicle`, `guest_rating`. - `GET /properties/{propertyId}/guests/visit-count?phone=...` - Access: property member. - Stores data: reads `guest`, booking count from `booking`. - `POST /properties/{propertyId}/guests/{guestId}/vehicles` - Request: `GuestVehicleRequest`. - Access: property member. - Stores data: inserts/updates `guest_vehicle`. - `POST /properties/{propertyId}/guests/{guestId}/signature` - Multipart SVG file. - Access: `ADMIN`/`MANAGER`. - Stores data: writes file under documents root; updates `guest.signature_path`. - `GET /properties/{propertyId}/guests/{guestId}/signature/file` - Access: property member. - Stores data: reads signature file path from `guest`. ### Guest documents - `POST /properties/{propertyId}/guests/{guestId}/documents?bookingId=...` - Multipart file. - Access: `ADMIN`/`MANAGER`. - Stores data: writes document file under docs root; inserts `guest_document`; queues AI extraction and updates `guest_document.extracted_data`. - `GET /properties/{propertyId}/guests/{guestId}/documents` - Access: `ADMIN`/`MANAGER`. - Stores data: reads `guest_document`. - `GET /properties/{propertyId}/guests/{guestId}/documents/stream` - Access: `ADMIN`/`MANAGER`. - Stores data: no writes; SSE extraction updates. - `GET /properties/{propertyId}/guests/{guestId}/documents/{documentId}/file` - Access: public with token OR `ADMIN`/`MANAGER`. - Stores data: reads `guest_document` + filesystem. - `DELETE /properties/{propertyId}/guests/{guestId}/documents/{documentId}` - Access: `ADMIN`/`MANAGER`. - Stores data: deletes file + `guest_document` row (only OPEN/CHECKED_IN booking). ### Guest ratings - `POST /properties/{propertyId}/guests/{guestId}/ratings` - Request: `GuestRatingCreateRequest`. - Access: property member. - Stores data: inserts `guest_rating`. - `GET /properties/{propertyId}/guests/{guestId}/ratings` - Access: property member. - Stores data: reads `guest_rating`. ## 12) Inbound Email APIs - `GET /properties/{propertyId}/inbound-emails/{emailId}/file` - Access: `ADMIN`/`MANAGER`. - Stores data: reads `inbound_email.raw_pdf_path` and PDF file. - `POST /properties/{propertyId}/inbound-emails/manual` - Multipart PDF. - Access: `ADMIN`/`MANAGER`. - Stores data: writes PDF under `/docs/emails`; inserts `inbound_email`; triggers ingestion workflow. ## 13) Rate plan APIs - `POST /properties/{propertyId}/rate-plans` - Request: `RatePlanCreateRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: inserts `rate_plan`. - `GET /properties/{propertyId}/rate-plans?roomTypeCode=...` - Access: property member. - Stores data: reads `rate_plan`. - `PUT /properties/{propertyId}/rate-plans/{ratePlanId}` - Request: `RatePlanUpdateRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: updates `rate_plan`. - `DELETE /properties/{propertyId}/rate-plans/{ratePlanId}` - Access: `ADMIN`/`MANAGER`. - Stores data: deletes `rate_calendar` rows for plan, then deletes `rate_plan`. - `POST /properties/{propertyId}/rate-plans/{ratePlanId}/calendar` - Request: `RateCalendarRangeUpsertRequest`. - Access: `ADMIN`/`MANAGER`. - Stores data: upserts `rate_calendar` rows in date range. - `GET /properties/{propertyId}/rate-plans/{ratePlanId}/calendar?from=...&to=...` - Access: property member. - Stores data: reads `rate_calendar` + `rate_plan`; returns average. - `DELETE /properties/{propertyId}/rate-plans/{ratePlanId}/calendar/{rateDate}` - Access: `ADMIN`/`MANAGER`. - Stores data: deletes one `rate_calendar` override row. ## 14) Razorpay APIs ### Settings + return + webhook - `GET /properties/{propertyId}/razorpay-settings` - Access: `ADMIN`/`MANAGER`. - Stores data: reads `razorpay_settings`. - `PUT /properties/{propertyId}/razorpay-settings` - Request: `RazorpaySettingsUpsertRequest`. - Access: `ADMIN`. - Stores data: inserts/updates `razorpay_settings`. - `POST /properties/{propertyId}/razorpay/webhook` - Access: public (signature validated). - Stores data: inserts `razorpay_webhook_log`, inserts `razorpay_payment_attempt`, updates `razorpay_qr_request` / `razorpay_payment_link_request`, inserts `payment` for capture/refund events. - `POST /properties/{propertyId}/razorpay/return/success` - Access: public. - Stores data: none. - `POST /properties/{propertyId}/razorpay/return/failure` - Access: public. - Stores data: none. ### QR + links + request close + refund - `POST /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr` - Request: `RazorpayQrGenerateRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: inserts `razorpay_qr_request` (or returns active existing). - `GET /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/active` - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: reads `razorpay_qr_request`. - `POST /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/close` - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: updates latest active `razorpay_qr_request.status`. - `POST /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/{qrId}/close` - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: updates specific `razorpay_qr_request.status`. - `GET /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/{qrId}/events` - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: reads `razorpay_webhook_log`. - `GET /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr/{qrId}/events/stream` - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: SSE stream only. - `GET /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/qr` - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: reads `razorpay_qr_request`. - `POST /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/payment-link` - Request: `RazorpayPaymentLinkCreateRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: inserts `razorpay_payment_link_request` (or returns existing open one). - `GET /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/requests` - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: reads open `razorpay_qr_request` + `razorpay_payment_link_request`. - `POST /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/close` - Request: `RazorpayPaymentRequestCloseRequest`. - Access: `ADMIN`/`MANAGER`/`STAFF`. - Stores data: updates closed status in corresponding Razorpay request row. - `POST /properties/{propertyId}/bookings/{bookingId}/payments/razorpay/refund` - Request: `RazorpayRefundRequest`. - Access: `ADMIN`/`MANAGER`/`FINANCE`. - Stores data: no local insert here; refund call is external and webhook later records ledger entry. --- ## Detailed example (as requested format) ### Expected checkout planning API **Expected checkout API is:** `POST /properties/{propertyId}/bookings/{bookingId}/expected-dates` **What it does:** - Updates planned dates on booking (`expectedCheckinAt`, `expectedCheckoutAt`), not actual checkout. - For `OPEN` bookings: can update both expected check-in and expected check-out. - For `CHECKED_IN`: can update only `expectedCheckOutAt` (check-in change is blocked). - For `CHECKED_OUT` / `CANCELLED` / `NO_SHOW`: returns conflict (`Booking closed`). - Validates range: if both are present, checkout must be after checkin. - Returns `204 No Content`. - Emits booking SSE update event. **Request body (`BookingExpectedDatesUpdateRequest`):** ```json { "expectedCheckInAt": "2026-02-05T12:00:00+05:30", "expectedCheckOutAt": "2026-02-06T11:00:00+05:30" } ``` **Allowed roles:** - `ADMIN`, `MANAGER`, `STAFF` (property-scoped) - `superAdmin` can also access (bypasses property membership/role checks) - Requires authenticated Firebase principal (`MyPrincipal`) **Data store:** - Updates row in `booking` table (`expected_checkin_at`, `expected_checkout_at`, `updated_at`) **Error codes:** - `400 Bad Request` - Invalid timestamp format (`"Invalid timestamp"`) for `expectedCheckInAt` / `expectedCheckOutAt` - Invalid range (`"Invalid date range"`) when checkout is not after check-in - `401 Unauthorized` - Missing auth principal / user not found - `403 Forbidden` - Authenticated but not a property member or missing role (`ADMIN`, `MANAGER`, `STAFF`) - `404 Not Found` - Booking not found, or booking does not belong to that property - `409 Conflict` - `"Cannot change expected check-in after check-in"` - `"Booking closed"` for `CHECKED_OUT`, `CANCELLED`, `NO_SHOW`