Bookings - Authenticated
Base path: /api/v1/bookings
Used by: customer-booki-web-app · Role: customer
organizationId: From the customer's JWT token (embedded at registration — sent automatically via Authorization: Bearer header)
These endpoints require authentication (Authorization: Bearer <accessToken> header) and are used by registered customers to manage their bookings.
POST /api/v1/bookings — Create Booking (Authenticated)
Auth: Protected (Authorization: Bearer <accessToken>)
Used by: customer-booki-web-app · Role: customer
Description: Create a booking as an authenticated customer. Logs booking in customer's history.
Request
{
"packageId": "69de52bc4f3e4272e30c7a15",
"bookingDate": "2026-04-20",
"bookingTime": "14:30",
"preferredPaymentMethod": "maya" // (optional)
}
Fields:
packageId(string, required): Service package ID (24-hex)bookingDate(string, required):YYYY-MM-DD(future)bookingTime(string, required):HH:MM(future)preferredPaymentMethod(string, optional):cashormaya
Note:
organizationIdis not sent in the request body. It is read from the customer's JWT token server-side.
Response (201 Created)
{
"message": "Your booking reservation has been submitted. You can view and manage it anytime from your dashboard.",
"bookingId": "69defc2e27e1a548fd0cce1c"
}
Error Responses
401 Unauthorized — No valid token:
{
"statusCode": 401,
"message": "Access token is required to proceed."
}
400 Bad Request — Past date/time:
{
"statusCode": 400,
"message": "Please select a valid date for your booking. Past dates are not available."
}
cURL Example
curl -X POST http://localhost:4001/api/v1/bookings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGc..." \
-d '{
"packageId": "69de52bc4f3e4272e30c7a15",
"bookingDate": "2026-04-20",
"bookingTime": "14:30",
"preferredPaymentMethod": "maya"
}'
GET /api/v1/bookings — List Customer Bookings
Auth: Protected (Authorization: Bearer <accessToken>)
Used by: customer-booki-web-app · Role: customer
organizationId: From JWT token (filters results to customer's organization automatically)
Description: Retrieve all bookings for the authenticated customer.
Request
Query Parameters (optional):
page(number, default: 1): Page numberlimit(number, default: 10, max: 100): Results per pagestatus(string): Filter by booking status. Accepted values:pending-verification,verified,pending,confirmed,declined,pending-reschedule,confirmed-reschedule,declined-reschedule,rescheduled,pending-cancel,confirmed-cancel,declined-cancel,cancelled,cancelled-admin,paid,ongoing,completed,no-show,unpaid-expired,expiredsearch(string): Search term (max 100 chars)sort(string, default:_id): Sort fieldorder(string, default:desc):ascordesc
GET /api/v1/bookings?page=1&limit=10&status=confirmed&order=desc
Response (200 OK)
{
"items": [
{
"_id": "507f1f77bcf86cd799439041",
"organizationId": "507f191e810c19729de860ea",
"packageId": "507f1f77bcf86cd799439031",
"bookingDate": "2026-04-10",
"bookingTime": "14:30",
"status": "confirmed",
"preferredPaymentMethod": "maya",
"createdAt": "2026-04-01T09:15:00Z"
},
{
"_id": "507f1f77bcf86cd799439042",
"organizationId": "507f191e810c19729de860ea",
"packageId": "507f1f77bcf86cd799439032",
"bookingDate": "2026-04-15",
"bookingTime": "10:00",
"status": "pending",
"createdAt": "2026-04-01T10:20:00Z"
}
],
"pages": 3,
"pageRange": "1-2 of 25"
}
Error Responses
401 Unauthorized — No token:
{
"statusCode": 401,
"message": "Access token is required to proceed."
}
cURL Example
curl -X GET "http://localhost:4001/api/v1/bookings?page=1&limit=10&status=confirmed" \
-H "Authorization: Bearer eyJhbGc..."
PUT /api/v1/bookings/:id/reschedule — Reschedule Booking
Auth: Protected (Authorization: Bearer <accessToken>)
Used by: customer-booki-web-app · Role: customer
Description: Reschedule an existing booking to a new date/time.
Request
{
"bookingDate": "2026-04-12",
"bookingTime": "16:00",
"rescheduleReason": "Customer requested new time due to schedule conflict"
}
Fields:
bookingDate(string, required): New date (YYYY-MM-DD, future)bookingTime(string, required): New time (HH:MM, future)rescheduleReason(string, optional): Reason for reschedule (10-500 chars)
Note:
bookableIdandorganizationIdare not sent in the request body. Both are read from the customer's JWT token server-side.
Response (200 OK)
Response message depends on the booking's current status:
{
"message": "Your booking has been successfully rescheduled. We hope to see you again soon!"
}
{
"message": "We've received your reschedule request. You'll receive a notification once it's reviewed and a decision is made."
}
Error Responses
400 Bad Request — New time is in past:
{
"statusCode": 400,
"message": "Please select a valid time slot for your rescheduled booking. Past date and time are not available."
}
cURL Example
curl -X PUT "http://localhost:4001/api/v1/bookings/507f1f77bcf86cd799439041/reschedule" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGc..." \
-d '{
"bookingDate": "2026-04-12",
"bookingTime": "16:00",
"rescheduleReason": "Customer requested new time"
}'
PUT /api/v1/bookings/:id/cancel — Cancel Booking
Auth: Protected (Authorization: Bearer <accessToken>)
Used by: customer-booki-web-app · Role: customer
Description: Cancel an existing booking.
Request
{
"cancelReason": "Had to travel for urgent business meeting"
}
Fields:
cancelReason(string, optional): Reason for cancellation (10-500 chars)
Note:
bookableIdandorganizationIdare not sent in the request body. Both are read from the customer's JWT token server-side.
Response (200 OK)
Response message depends on the booking's current status:
{
"message": "Your booking has been successfully cancelled. We hope to see you again soon!"
}
{
"message": "We've received your cancellation request. You'll receive a notification once it's reviewed and a decision is made."
}
Error Responses
400 Bad Request — Booking cannot be cancelled:
{
"statusCode": 400,
"message": "This booking can no longer be cancelled."
}
cURL Example
curl -X PUT "http://localhost:4001/api/v1/bookings/507f1f77bcf86cd799439041/cancel" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGc..." \
-d '{
"bookableId": "507f1f77bcf86cd799439051",
"cancelReason": "Had to travel"
}'
Booking Status Lifecycle
PENDING → CONFIRMED (owner accepts)
→ DECLINED (owner declines)
→ RESCHEDULED (customer reschedules)
→ CANCELLED (customer cancels)
→ NO_SHOW (customer doesn't show up)
- New bookings start as
PENDINGuntil owner confirms. CONFIRMEDbookings can be rescheduled or cancelled by customer.DECLINEDbookings cannot be modified; customer must rebook.CANCELLEDbookings are soft-deleted (markdeletedAt).
Notes
- All authenticated endpoints require a valid
Authorization: Bearer <accessToken>header. - Dates must be in the future; past dates are rejected.
- Pagination defaults to page 1, limit 10 (max 100).
- See
booki-api/src/validations/booking.validation.tsfor validation rules.
