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:

  1. An admin creates an API user (UserName, Password, OfficeId) in /admin.
  2. The client calls CreateSession and receives a SessionId.
  3. The SessionId is sent in the body of every HotelAvailability call (15-minute sliding expiry — each successful call renews it).

Base URL & format

ItemValue
Base URLhttps://bookapp.pro.plus
Content-Typeapplication/json
CurrencyAll monetary values are USD
EnvelopeEvery response has Success (bool) and Error (object|null)

Business rules (applied to every result)

  1. 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.
  2. Review score “Good 7+” only. Lower-rated properties are excluded.
  3. Sorted by cheapest price (ascending) by default.

CreateSession

POST/Authenticate/CreateSession

Establishes a session. Credentials are the API user created in the admin panel.

Request body

FieldTypeReqDescription
OfficeIdstringyesThe API user's Office ID.
UserNamestringyesThe API user's username.
PasswordstringyesSHA-512 of the account UUID, uppercasedstrtoupper(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
}
Session validity: 15 minutes, sliding — renewed on each authenticated request.

EndSession

POST/Authenticate/EndSession

Request body

FieldTypeReqDescription
SessionIdstringyesThe session to terminate.

Response

{ "Success": true, "Error": null }

HotelAvailability

POST/Hotel/HotelAvailability

One endpoint, two modes, selected by which id you send:

Request body

FieldTypeReqDescription
SessionIdstringyesFrom CreateSession.
CheckIndate YYYY-MM-DDyesArrival date.
CheckOutdate YYYY-MM-DDyesDeparture date.
CityIdintegercond.City id from cities/search. Required for city search. Null when using HotelId.
HotelIdintegercond.Property id. Required for hotel details. Null for city search.
CountryCodestring (ISO-2)noAccepted; informational.
NationalityIdstringnoGuest nationality; informational.
OccupanciesarraynoOne object per room: {AdultCount, ChildCount, ChildAges[]}. Defaults to 1 room / 2 adults.
DeepbooleannoCity search only. true → up to 2000 results via property-type bucketing (else ~1000/query cap).
langstring (2-letter)noContent language for hotel/room text (see Languages). Missing / null / unsupported → en. Prices are always USD regardless of language.

Mode A — City search

Returns PricedItineraries (hotels), cheapest first. Rooms is empty here; call by HotelId for the room breakdown.

// Request
{
  "SessionId": "7ce0…985a03",
  "CheckIn": "2026-09-10",
  "CheckOut": "2026-09-12",
  "CityId": -2140479,
  "CountryCode": "NL",
  "NationalityId": "NL",
  "Occupancies": [ { "AdultCount": 2, "ChildCount": 0, "ChildAges": [] } ],
  "Deep": false
}

// Response (truncated)
{
  "Success": true,
  "PricedItineraries": [
    {
      "FareSourceCode": "NjMzMTg2MnwyMDI2LTA5LTEwfDIwMjYtMDktMTI=",
      "HotelId": 5901512,
      "HotelName": "Dutchies Hostel",
      "NetRate": 182.06,
      "Currency": "USD",
      "NonRefundable": true,
      "Hotel": {
        "name": "Dutchies Hostel",
        "rating": 0,
        "reviewScore": 8.9,
        "location": { "latitude": 52.37, "longitude": 4.90 },
        "images": [ "https://bookapp.pro.plus/live_images/xdata/images/hotel/square60/58458024.jpg?k=…&o=" ]
      },
      "Rooms": [],
      "CancellationPolicies": []
    }
  ],
  "Meta": { "CityId": -2140479, "TotalOnBooking": 266, "Returned": 257, "Deep": false, "Plan": null },
  "Error": null
}

Mode B — Hotel details

Returns a single PricedItinerary with the full, prepaid Rooms list.

// Request
{
  "SessionId": "7ce0…985a03",
  "CheckIn": "2026-09-10",
  "CheckOut": "2026-09-12",
  "CityId": null,
  "HotelId": 6331862,
  "Occupancies": [ { "AdultCount": 2 } ]
}

// Response (truncated)
{
  "Success": true,
  "PricedItineraries": [
    {
      "FareSourceCode": "NjMzMTg2MnwyMDI2LTA5LTEwfDIwMjYtMDktMTI=",
      "HotelId": 6331862,
      "HotelName": "Holiday Inn Express Amsterdam - North Riverside",
      "NetRate": 775.62,
      "Currency": "USD",
      "NonRefundable": false,
      "Hotel": {
        "name": "…", "address": "…", "city": "Amsterdam",
        "rating": 3, "reviewScore": 8.2,
        "location": { "latitude": 52.38, "longitude": 4.91 },
        "images": [ "https://bookapp.pro.plus/images/xdata/images/hotel/max500/337421613.jpg" ]
      },
      "Rooms": [
        {
          "RoomId": "633186210_247251398_2_41_0",
          "RoomName": "Standard Twin Room …",
          "RoomType": "Buffet breakfast is included in the room rate.",
          "Price": 775.62,
          "Currency": "USD",
          "Occupancy": 2,
          "Amenities": [ "Free WiFi", "Air conditioning", "…" ],
          "Beds": [ "2 single beds" ],
          "Images": [ "https://bookapp.pro.plus/live_images/xdata/images/room/…jpg?k=…&o=" ],
          "RoomsLeft": 6,
          "NonRefundable": false,
          "Prepayment": "full_prepayment"
        }
      ],
      "CancellationPolicies": [ { "FromDate": "2026-09-08 …", "Penalty": 0 } ]
    }
  ],
  "Error": null
}

PricedItinerary fields

FieldTypeDescription
FareSourceCodestringOpaque; treat as-is.
HotelIdintegerProperty id (use it for Mode B).
HotelNamestringProperty name.
NetRatenumberTotal price for the stay, USD.
NonRefundablebooleanTrue if no refundable option exists.
Hotelobject{name, rating (0–5), reviewScore, location{latitude,longitude}, images[]}.
RoomsarrayEmpty in city search; populated in hotel details.
CancellationPoliciesarray{FromDate, Penalty} per room.
GET/Hotel/cities/search?q=istanbul&provider=example-provider-1&limit=50

Find cities by name. Public (no session). Returns an internal id (use it as HotelAvailability CityId) and the provider-side external_id.

Query parameters

ParamTypeReqDescription
qstringyesCity name query.
providerstringnoInventory source id (echoed in meta).
limitintegernoMax 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

POST/Hotel/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" } }
A city must have been seen via 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:

FormMeaning
…/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." } }
IdHTTPMeaning
Err0101001400Missing OfficeId / UserName / Password.
Err0101003401Invalid credentials or inactive account.
Err0201001401Invalid or expired SessionId.
Err0201002400CheckIn / CheckOut missing.
Err0201003400Neither CityId nor HotelId provided.
Err0201004200No 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}]}'