API docs · 17 Aug 2026
API updates for mobile developers
New and changed endpoints. All money is ETB. Envelope: { "status", "message", "timestamp", "data" }. Protected calls: Authorization: Bearer <token>.
Guest base: https://zemenbooking.com/api/v1/mobile
Unified login: https://zemenbooking.com/api/v1/auth/login
Staff / hotel admin: https://zemenbooking.com/api/v1/staff
This server: http://196.188.249.180/zemenbooking/api/v1/mobile
1. Unified login
One screen for guest and hotel-admin. Do not try guest login then fall back to staff login — a wrong password would hit rate limits twice.
POST https://zemenbooking.com/api/v1/auth/login · same handler: POST https://zemenbooking.com/api/v1/mobile/auth/login
{
"email": "abebe@example.com",
"password": "secret123"
}
Optional user_type: "guest" or "hotel_admin" if the same email exists in both tables (otherwise 409).
Branch on data.user_type — "guest" or "hotel_admin".
Guest success
{
"status": "success",
"data": {
"user_type": "guest",
"token": "eyJ…",
"token_type": "Bearer",
"expires_in": 2592000,
"user": {
"id": 42,
"uuid": "…",
"user_type": "guest",
"role": "guest",
"first_name": "Abebe",
"last_name": "Kebede",
"email": "abebe@example.com",
"phone": "+251911234567",
"avatar_url": null,
"loyalty_points": 0,
"total_bookings": 3,
"status": "active",
"email_verified": true
}
}
}
Guest token has no aud. Use it on /api/v1/mobile/….
Hotel admin success
{
"status": "success",
"data": {
"user_type": "hotel_admin",
"token": "eyJ…",
"token_type": "Bearer",
"expires_in": 86400,
"hotel_id": 1,
"user": {
"id": "uuid-string",
"name": "Hotel Admin",
"email": "hotel.admin@zemenbooking.com",
"user_type": "hotel_admin",
"role": "hotel-owner",
"role_slug": "hotel-owner",
"role_name": "Hotel Owner"
}
}
}
Staff token has aud: "staff" and hotel_id. Use it on /api/v1/staff/….
401wrong email/password403guest not active, or staff has no hotel409email matches both accounts — senduser_type
Test hotel admin: hotel.admin@zemenbooking.com / HotelAdmin@2026
2. Notifications (guest JWT)
Mark-as-read now persists. notification_id is an integer. is_read is a real boolean.
GET https://zemenbooking.com/api/v1/mobile/notifications
{
"data": {
"count": 2,
"unread": 1,
"items": [
{
"notification_id": 133,
"type": "booking_confirmed",
"title": "Booking confirmed",
"message": "Your stay ZB123 is confirmed.",
"data": { "booking_id": 10, "confirmation_code": "ZB123" },
"is_read": false,
"read_at": null,
"created_at": "2026-08-17 09:00:00"
}
]
}
}
PATCH https://zemenbooking.com/api/v1/mobile/notifications/{id}/read (also POST)
{ "data": { "notification_id": 133, "is_read": true, "read_at": "2026-08-17 10:15:00", "affected": 1 } }
New: POST https://zemenbooking.com/api/v1/mobile/notifications/mark-all-read
{ "data": { "affected": 4, "unread": 0 } }
3. Hotel reviews
New (public): GET https://zemenbooking.com/api/v1/mobile/hotels/{id}/reviews?page=1&limit=10
Approved only. limit max 50.
{
"data": {
"hotel_id": 1,
"total": 5,
"page": 1,
"limit": 10,
"total_pages": 1,
"average_rating": 4.6,
"rating_distribution": { "5": 4, "4": 1, "3": 0, "2": 0, "1": 0 },
"reviews": [
{
"review_id": 12,
"rating": 5,
"title": "Great stay",
"comment": "Clean rooms and friendly staff.",
"is_verified_purchase": true,
"status": "approved",
"reply": "Thank you!",
"replied_at": "2026-08-16 14:00:00",
"created_at": "2026-08-15 11:00:00",
"reviewer": { "first_name": "Abebe", "last_initial": "K.", "display_name": "Abebe K." }
}
]
}
}
POST https://zemenbooking.com/api/v1/mobile/hotels/{id}/reviews (guest JWT)
{ "rating": 5, "title": "Great stay", "comment": "Clean rooms and friendly staff.", "booking_id": 10 }
Created as pending — it will not show on GET until approved.
4. Hotel admin writes (/api/v1/staff)
Use the staff token from unified login (user_type: hotel_admin).
| Method | Path | Body |
|---|---|---|
| GET / PUT | /hotel | Partial hotel fields (name, phone, email, address, city, stars, description, check-in/out). PUT /profile is the same. |
| POST | /rooms | room_number, room_type_id, optional room_floor, room_status, room_notes |
| PUT | /rooms/{id} | Same fields, all optional |
| POST | /room-types | room_type_name, room_type_capacity, room_type_bed_type, optional price_per_night |
| PUT | /room-types/{id} | Same fields, all optional |
Update hotel
PUT https://zemenbooking.com/api/v1/staff/hotel
{ "hotel_phone": "+251911234567", "hotel_check_in_time": "14:00", "hotel_check_out_time": "11:00" }
Create room
POST https://zemenbooking.com/api/v1/staff/rooms
{ "room_number": "401", "room_type_id": 3, "room_floor": 4, "room_status": "available" }
Create room type
POST https://zemenbooking.com/api/v1/staff/room-types
{ "room_type_name": "Deluxe King", "room_type_capacity": 2, "room_type_bed_type": "king", "price_per_night": 4500 }
room_status: available, occupied, occupied_dirty, maintenance, cleaning, out_of_service.
room_type_bed_type: single, double, queen, king, twin, triple, family, bunk, sofa_bed.
Quick curl
curl -sS -X POST https://zemenbooking.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"abebe@example.com","password":"secret123"}'
curl -sS "https://zemenbooking.com/api/v1/mobile/hotels/1/reviews?page=1&limit=10"
curl -sS -X PATCH https://zemenbooking.com/api/v1/mobile/notifications/133/read \
-H "Authorization: Bearer $TOKEN"
curl -sS -X POST https://zemenbooking.com/api/v1/mobile/notifications/mark-all-read \
-H "Authorization: Bearer $TOKEN"
curl -sS -X PUT https://zemenbooking.com/api/v1/staff/hotel \
-H "Authorization: Bearer $STAFF_TOKEN" \
-H "Content-Type: application/json" \
-d '{"hotel_phone":"+251911234567"}'
Markdown copy: docs/API-UPDATES-FOR-DEVELOPERS.md in the repo. Full catalog: http://196.188.249.180/zemenbooking/developers.