BookApp API
A Hermeseus-compatible hotel API. Search availability, get per-hotel room pricing, all normalized to
USD. Authentication and the /Hotel/HotelAvailability contract mirror the
Hermeseus shape so existing integrations map over with minimal changes.
Visual demo: /try Admin panel: /admin API Playground: /playground
Overview
Every call is POST with a JSON body (except the GET helpers). The flow is:
- An admin creates an API user (UserName, Password, OfficeId) in /admin.
- The client calls CreateSession and receives a
SessionId. - The
SessionIdis sent in the body of every HotelAvailability call (15-minute sliding expiry — each successful call renews it).
Base URL & format
| Item | Value |
|---|---|
| Base URL | https://bookapp.pro.plus |
| Content-Type | application/json |
| Currency | All monetary values are USD |
| Envelope | Every response has Success (bool) and Error (object|null) |
Business rules (applied to every result)
- Online / prepaid only. Pay-at-property and "no prepayment" offers are removed — at the search level and per-room. Nothing that charges the guest at the hotel is returned.
- Review score “Good 7+” only. Lower-rated properties are excluded.
- Sorted by cheapest price (ascending) by default.
CreateSession
Establishes a session. Credentials are the API user created in the admin panel.
Request body
| Field | Type | Req | Description |
|---|---|---|---|
OfficeId | string | yes | The API user's Office ID. |
UserName | string | yes | The API user's username. |
Password | string | yes | SHA-512 of the account UUID, uppercased — strtoupper(hash('sha512', uuid)). Find the UUID / ready-made password in /admin (API Users) or the Playground (auto-filled). |
Response
{
"Success": true,
"SessionId": "7ce01b22-df26-465f-b143-a532ed985a03",
"Error": null
}
EndSession
Request body
| Field | Type | Req | Description |
|---|---|---|---|
SessionId | string | yes | The session to terminate. |
Response
{ "Success": true, "Error": null }
HotelAvailability
One endpoint, two modes, selected by which id you send:
- City search — send
CityId(leaveHotelIdnull) → a list of hotels. - Hotel details — send
HotelId(leaveCityIdnull) → one hotel with full room pricing.
Request body
| Field | Type | Req | Description |
|---|---|---|---|
SessionId | string | yes | From CreateSession. |
CheckIn | date YYYY-MM-DD | yes | Arrival date. |
CheckOut | date YYYY-MM-DD | yes | Departure date. |
CityId | integer | cond. | City id from cities/search. Required for city search. Null when using HotelId. |
HotelId | integer | cond. | Property id. Required for hotel details. Null for city search. |
CountryCode | string (ISO-2) | no | Accepted; informational. |
NationalityId | string | no | Guest nationality; informational. |
Occupancies | array | no | One object per room: {AdultCount, ChildCount, ChildAges[]}. Defaults to 1 room / 2 adults. |
Deep | boolean | no | City search only. true → up to 2000 results via property-type bucketing (else ~1000/query cap). |
lang | string (2-letter) | no | Content language for hotel/room text (see Languages). Missing / null / unsupported → en. Prices are always USD regardless of language. |
The response envelope is the same for both modes:
{
"Success": true,
"SearchId": 766002844,
"Error": null,
"CheckIn": "2026-09-21T00:00:00",
"CheckOut": "2026-09-23T00:00:00",
"PricedItineraries": [ /* one offer object per result — see schema below */ ]
}
Mode A — City search
One offer per hotel (its cheapest prepaid rate), cheapest first. In city search
FareSourceCode is empty ("").
// Request
{ "SessionId":"7ce0…985a03", "CheckIn":"2026-09-21", "CheckOut":"2026-09-23",
"CityId": 12, "CountryCode":"TR", "NationalityId":"TR",
"Occupancies":[{"AdultCount":2,"ChildCount":0,"ChildAges":[]}], "Deep": false, "lang":"en" }
Mode B — Hotel details
Send HotelId (and CityId:null). Returns one offer per available room-rate
for that hotel; here FareSourceCode is a real code, and the shared Hotel object carries the full
facility_groups and image gallery.
// Request
{ "SessionId":"7ce0…985a03", "CheckIn":"2026-09-21", "CheckOut":"2026-09-23",
"CityId": null, "HotelId": 11036392, "Occupancies":[{"AdultCount":2}], "lang":"en" }
PricedItinerary (offer) schema
Every item in PricedItineraries is a full offer object:
{
"FareSourceCode": "", // empty in city search; a code in hotel-details
"Offer": null, "Promotion": "Special Offer" | null,
"NonRefundable": true,
"HotelId": 11036392,
"HotelPolicy": { "MinAge": null, "CheckOutTime": null, "PetAttribiute": [], … },
"ExtraCharge": null,
"PaymentDeadline": null, "PaymentDeadlineTimeZone": "Asia/Tehran",
"Currency": "USD",
"AvailableRoom": 9,
"NetRate": 160.19, "NetRateWithoutDiscount": 0, "ExtraBedRate": 0, "BaseRate": 0,
"HotelRateInclusions": {
"Amenties": [], "Offers": [],
"MealTypes": ["Room only"],
"Promotions": [ { "Name": "Special Offer", "Id": null, "CategoryPriority": 0, … } ]
},
"NightlyList": [],
"Rooms": [ {
"RoomId": "41570930", "RoomMapId": "9219510-253",
"Name": "1 King Bed, Deluxe, Non Smoking", "RoomMapName": "Standard Room with 1 King Bed",
"AdultCount": 2, "ExtraBedCount": 0, "ChildCount": 0, "ChildAges": null,
"MealType": "Room Only", "MealTypeCategory": "Room only",
"SharingBedding": false, "BedGroups": null,
"HotelRoomEarlyCheckin": null, "HotelRoomLateCheckout": null
} ],
"Surcharges": [], "CancellationPolicies": [], "Remarks": [], "RemarksFa": [], "Amenities": [],
"IsReserveOffline": false, "IsBlockout": false, "IsMinStayNight": false, "MinStayNight": 0, …,
"HotelRefundType": "Offline",
"NationalityRule": null, "OtherNationalities": [],
"PricedItineraryTransfers": [], "HotelPricedItineraryMetaDatas": [], "HotelLabels": [], "HotelLabelsFa": [],
"Hotel": {
"id": null, "external_id": 11036392,
"name": "Tryp By Wyndham Istanbul Sancaktepe",
"rating": null, "review_score": 7.6, "last_update": null,
"contact": { "phone": null, "fax": null, "email": null, "url": null },
"address": {
"line": "…", "postal_code": null,
"city": { "id": 12, "external_id": -755070, "name": "Istanbul" },
"destination": { "id": 12, "external_id": -755070, "name": "Istanbul" },
"country": { "id": null, "code": "TR", "name": "Turkey" }
},
"location": { "latitude": 40.98, "longitude": 29.22 },
"accommodation": { "id": null, "external_id": 204, "name": "Hotels" },
"chain": null,
"facility_groups": [ { "id": 1, "name": "General",
"facilities": [ { "id": 2, "external_id": 2, "name": "Parking" } ] } ],
"images_count": 6,
"images": [
{ "url": "https://bookapp.pro.plus/images/xdata/images/hotel/max500/509902851.jpg",
"thumbnail_url": "https://bookapp.pro.plus/images/xdata/images/hotel/square60/509902851.jpg" }
]
}
}
Hotel.images are objects
{url, thumbnail_url} on our domain (see Image URLs). In city search
each hotel has one main image and facility_groups:[]; the full gallery + facilities come in
hotel-details. CityId is the internal id from
cities/search.cities/search
Find cities by name. Public (no session). Returns an internal id (use it as
HotelAvailability CityId) and the provider-side external_id.
Query parameters
| Param | Type | Req | Description |
|---|---|---|---|
q | string | yes | City name query. |
provider | string | no | Inventory source id (echoed in meta). |
limit | integer | no | Max results (default 50, max 100). |
{
"data": [
{ "id": 12, "external_id": -755070, "name": "Istanbul",
"destination": "Istanbul, Turkey", "country": { "code": "TR", "name": "Turkey" } }
],
"meta": { "query": "istanbul", "count": 1, "limit": 50, "provider": "example-provider-1" }
}
cities/lookup
Bulk-resolve cities by their provider-side external_id (up to 500).
// Request
{ "external_ids": [-755070, -2140479], "provider": "example-provider-1" }
// Response
{ "data": [ { "id": 12, "external_id": -755070, "name": "Istanbul", … } ],
"meta": { "count": 1, "requested": 2, "provider": "example-provider-1" } }
cities/search before it can be resolved by cities/lookup.Not implemented (by design)
/Hotel/HotelBook, /Hotel/HotelOrder, /Hotel/HotelCancel and
/Hotel/HotelBookingData are intentionally absent — this service covers search & availability only.
Languages
Send a 2-letter lang in the request body to translate hotel and room content
(names, room types, meal plans, addresses, review words, …). Prices are always returned in USD,
independent of language. If lang is omitted, null, or not in the list below,
the response falls back to en (echoed back in Meta.Language).
Supported codes:
arbgcacs dadeelen esetfifr hehrhuid isitjako ltlvmsnl noplptro ruskslsr svthtruk vizh
// same search, German content — prices still USD
{ "SessionId":"", "CheckIn":"2026-09-10", "CheckOut":"2026-09-12",
"HotelId":6331862, "lang":"de", "Occupancies":[{"AdultCount":2}] }
// → Rooms[0].RoomName: "Standard-Zweibettzimmer …", Currency: "USD"
Image URLs
All image URLs point to bookapp.pro.plus and are cached on our side:
| Form | Meaning |
|---|---|
…/live_images/<path>?k=…&o= | Not cached yet. First request fetches from source, stores it permanently, then serves it. |
…/images/<path> | Already cached — served from our storage (no token needed). |
Both return the raw image bytes with long-lived cache headers. Just use whichever URL the API returns.
Errors
On failure, Success is false and Error is populated:
{ "Success": false, "SessionId": null,
"Error": { "Id": "Err0101003", "Message": "Invalid credentials or inactive account." } }
| Id | HTTP | Meaning |
|---|---|---|
Err0101001 | 400 | Missing OfficeId / UserName / Password. |
Err0101003 | 401 | Invalid credentials or inactive account. |
Err0201001 | 401 | Invalid or expired SessionId. |
Err0201002 | 400 | CheckIn / CheckOut missing. |
Err0201003 | 400 | Neither CityId nor HotelId provided. |
Err0201004 | 200 | No available (prepaid) rooms for this hotel/date. |
Quick start (curl)
# 1) Create a session
curl -s https://bookapp.pro.plus/Authenticate/CreateSession \
-H 'Content-Type: application/json' \
-d '{"OfficeId":"OFFICE001","UserName":"demo","Password":"demo12345"}'
# 2) City search (cheapest-first, prepaid, 7+)
curl -s https://bookapp.pro.plus/Hotel/HotelAvailability \
-H 'Content-Type: application/json' \
-d '{"SessionId":"","CheckIn":"2026-09-10","CheckOut":"2026-09-12",
"CityId":-2140479,"Occupancies":[{"AdultCount":2}]}'
# 3) Hotel details (rooms + prices)
curl -s https://bookapp.pro.plus/Hotel/HotelAvailability \
-H 'Content-Type: application/json' \
-d '{"SessionId":"","CheckIn":"2026-09-10","CheckOut":"2026-09-12",
"CityId":null,"HotelId":6331862,"Occupancies":[{"AdultCount":2}]}'