Booking Engine API
REST API for embedding HotelBee's booking flow in third-party apps. Covers room availability, room types, currencies, reservations, promo codes, OTA price comparison, and the guest portal (login, profile, reservations, invoices, orders, online check-in).
Last updated: June 5, 2026
Overview
The HotelBee Booking Engine API allows third-party applications to integrate with HotelBee's booking system. This API enables you to:
- Retrieve room type catalogs, availability, and pricing
- Search for available rooms across date ranges
- Create reservations directly in HotelBee
- Validate promo codes for discounts
- Compare OTA channel prices
- Power a guest portal with self-service check-in, invoice viewing, and order history
This is a RESTful API that returns JSON responses and uses standard HTTP response codes.
Base URL
All API requests should be made to:
https://app.hotelbee.co/api/booking-engineAuthentication
The Booking Engine API uses two authentication methods depending on the endpoint type.
Public Booking Engine Authentication
All public booking engine endpoints require API key authentication.
Include these headers with every request:
- Authorization (string, required):
Bearer {api_key}— your API key (contact support@hotelbee.co to obtain) - Property (string, required): Your property name
- Username (string, required): Username associated with your API key
- Content-Type (string, required for POST):
application/jsonfor POST requests
ThePropertyheader is required on *every* endpoint — public booking
engine and guest portal alike. A request without it fails with400
("Property Missing"). Do not omit it, even on guest-token requests.
Example Authentication Headers
{
"Authorization": "Bearer your-api-key-here",
"Property": "myhotel",
"Username": "booking_engine"
}Guest Portal Authentication
Guest portal endpoints (except login and some public ones) require an additional JWT token obtained via the /guest-portal/login endpoint. This is sent alongside the API key headers — guest portal requests carry both the API key (Authorization, Property, Username) and the guest token.
- X-Guest-Token (string, required): JWT token obtained from
/guest-portal/login - Property (string, required): Your property name
- Plus the standard API key headers (
Authorization,Username).
Send the guest token only inX-Guest-Token. TheAuthorizationheader
always carries your API key, so the guest token must go inX-Guest-Token—
it is the only header that works for it.
Token Details:
- Expiry: 7 days. Treat the token as an opaque string.
What your key can do
Your key is scoped to the property (or properties) it was issued for. A few things to know:
- Property scope. A request whose
Propertyheader is not one your key was issued for is rejected with403 Forbidden. - Client search is not available to integration keys —
GET /clients/searchreturns403. - Discounts are applied by passing a
promoCode(see Create Reservation). - Payments go through Stripe (
/create-payment-intent) or, if enabled for your key, your own payment gateway (externalPayment). Sending raw card details is not supported and returns400 raw_card_not_supported.
To obtain a key, contact support@hotelbee.co with your company name, the property (or properties) you'll integrate, and whether you process payments on your own gateway.
Rate Limiting
Requests are rate limited per property and client IP. Exceeding a limit returns HTTP 429:
{ "error": "Too many requests. Please try again shortly." }| Endpoints | Limit | |---|---| | Reads (/availabilities, /roomtypes, /config, /currencies, /ota-prices, /guestcategories, /clients/search) and /quote | 120 / minute | | /reservations, /create-payment-intent | 10 / minute | | /promocode/validate | 15 / minute | | /guest-portal/login | 10 / 5 minutes |
Error Handling
The API uses standard HTTP status codes:
- 200 OK — Request successful
- 400 Bad Request — Missing required data or validation error
- 401 Unauthorized — Authentication failed
- 403 Forbidden — Your key is not authorized for this property, or for a feature it doesn't have access to
- 404 Not Found — Resource or property not found
- 429 Too Many Requests — Rate limit exceeded (see Rate Limiting)
- 500 Internal Server Error — Server error
Error responses use this format, where error is a stable code and message is optional human-readable text:
{
"error": "code",
"message": "optional human-readable text"
}Public Endpoints
Get Availability
Retrieves room availability and pricing for a given date range. Use this to show available room types and their daily rates on your booking widget.
GET /availabilities — Fetches daily room availability and pricing for a date range. Auth required (API key).
Query Parameters
- startDate (string, required): Start date in
YYYY-MM-DDformat - endDate (string, required): End date in
YYYY-MM-DDformat
Example Request
curl -X GET "https://app.hotelbee.co/api/booking-engine/availabilities?startDate=2026-04-01&endDate=2026-04-05" \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine"Response 200 — Success
{
"startDate": "2026-04-01",
"endDate": "2026-04-05",
"roomtypes": {
"roomtype_2026-01-15T10:00:00Z": {
"2026-04-01": {
"price": 100,
"includedCapacity": 2,
"capacity": [
{ "name": "Adults", "price": 25 },
{ "name": "Children", "price": 15 }
]
},
"2026-04-02": {
"price": 100,
"includedCapacity": 2,
"capacity": [
{ "name": "Adults", "price": 25 },
{ "name": "Children", "price": 15 }
]
}
}
},
"rates": {
"rate_2026-01-20T08:00:00Z": {
"roomtype_2026-01-15T10:00:00Z": {
"2026-04-01": {
"price": 90,
"includedCapacity": 2,
"capacity": [
{ "name": "Adults", "price": 20 }
]
}
}
}
},
"roomtypeQuantities": {
"roomtype_2026-01-15T10:00:00Z": 5
}
}Response 400 — Missing Parameters
{
"error": "startDate and endDate are required"
}Response Fields
- startDate (string): Requested start date
- endDate (string): Requested end date
- roomtypes (object): Map of room type ID → date → pricing (base rate pricing per day)
- rates (object): Map of rate ID → room type ID → date → pricing (rate-specific pricing per day)
- roomtypeQuantities (object): Map of room type ID → available room count
Pricing Object
- price (number): Base price per night for included capacity
- includedCapacity (integer): Number of guests included in the base price
- capacity (array): Extra guest charge tiers (name + price per additional guest)
Use Cases
- Display a date-range availability calendar
- Show pricing per night per room type
- Calculate total stay cost including extra guest charges
- Check room availability before creating a reservation
Get Room Types
Retrieves the complete room type catalog including details, amenities, images, bed types, services, and booking engine rates.
GET /roomtypes — Fetches all room types with full details, services, and rates. Auth required (API key). Optionally accepts a guest token.
Personalized rates: This endpoint runs optional guest authentication. If
you also send a validX-Guest-Token, the response includes client-specific
(private) rates targeted at that guest — i.e. rates whoseavailableTomatches
the guest's client ID — in addition to the public rates. Those private rates
are flagged withisClientSpecificRate: true. Without a guest token, only
public rates (availableTo: "all") are returned. An invalid or expired token
is ignored rather than rejected, so the call still succeeds with public rates.
Example Request
curl -X GET https://app.hotelbee.co/api/booking-engine/roomtypes \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine"Response 200 — Success
[
{
"id": "roomtype_2026-01-15T10:00:00Z",
"name": "Deluxe Room",
"description": "Spacious room with sea view",
"capacity": [
{ "name": "Adults", "price": 25 },
{ "name": "Children", "price": 15 }
],
"maxCapacity": 4,
"includedCapacity": 2,
"price": 100,
"images": [
"https://storage.blob.core.windows.net/hotel/room1.jpg"
],
"amenities": ["WiFi", "AC", "Mini Bar"],
"meals": ["breakfast"],
"bedtypes": [
{
"id": "bedtype_001",
"name": "Double Bed",
"capacity": 2,
"quantity": 1
}
],
"bookingEngineServices": [
{
"id": "service_spa_001",
"name": "Spa Access",
"code": "SPA001",
"calculationType": "per_night",
"frequency": "nightly",
"price": 25,
"taxData": [
{
"taxId": "tax_001",
"isIncluded": false,
"tax": { "rate": 20, "category": "VAT" }
}
]
}
],
"rates": [
{
"id": "rate_spring_001",
"name": "Spring Rate",
"roomTypes": ["roomtype_2026-01-15T10:00:00Z"],
"meals": ["breakfast"],
"maxCapacity": 4,
"includedCapacity": 2,
"minimumNights": 1,
"maximumNights": 30,
"minimumAdvance": 0,
"maximumAdvance": 365,
"availableTo": "all",
"services": [
{
"serviceId": "service_spa_001",
"isPriceIncluded": true,
"isInvoiceItem": false,
"service": {}
}
],
"lunchCalculation": null
}
]
}
]Response Fields
- id (string): Unique room type identifier
- name (string): Room type display name
- description (string): Room type description
- capacity (array): Extra guest charge tiers
- maxCapacity (integer): Maximum guest capacity
- includedCapacity (integer): Guests included in base price
- price (number): Default base price
- images (array): Image URLs
- amenities (array): List of amenity names
- meals (array): Included meal plans
- bedtypes (array): Bed configurations with capacity
- bookingEngineServices (array): Optional add-on services with pricing and tax data
- rates (array): Booking engine rates (only rates with
bookingEngineRate: true)
Rate Object Fields
- minimumNights (integer): Minimum stay length required
- maximumNights (integer): Maximum stay length allowed
- minimumAdvance (integer): Minimum days in advance to book
- maximumAdvance (integer): Maximum days in advance to book
- availableTo (string): Who can book this rate.
"all"for public rates, or a client ID for a private rate targeted at a specific guest - isClientSpecificRate (boolean):
trueonly when a guest token was sent and this rate is private to that guest. Absent/false for public rates - cancelationPolicyId (string | null): ID of the cancellation policy attached to the rate, if any
- cancelationPolicy (object | null): The resolved cancellation policy for the rate, if one is attached
- services (array): Services included/available with this rate
Get Configuration
Retrieves all booking engine configuration including branding, footer, language settings, property metadata, terms, and payment methods.
GET /config — Fetches booking engine configuration and branding. Auth required (API key).
Example Request
curl -X GET https://app.hotelbee.co/api/booking-engine/config \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine"Response 200 — Success
{
"branding": {
"hotelTitle": "Hotel Riviera",
"showHotelTitle": true,
"logo": "https://storage.blob.core.windows.net/hotel/logo.png",
"headerColor": "#1a237e",
"buttonColor": "#ff6f00",
"backgroundImage": "https://storage.blob.core.windows.net/hotel/bg.jpg",
"font": "Roboto",
"showPropertyAddress": true
},
"footer": {
"enabled": true,
"text": "© 2026 Hotel Riviera",
"links": [],
"contactEmail": "info@hotelriviera.com",
"contactPhone": "+355 69 123 4567",
"aboutUsText": "A luxury seaside hotel...",
"locationLink": "https://maps.google.com/?q=..."
},
"language": {
"enabledLanguages": ["en", "sq", "it"],
"defaultLanguage": "sq",
"showFlags": true
},
"propertyMeta": {
"name": "Hotel Riviera",
"address": "Rruga e Plazhit",
"city": "Durrës",
"region": "Albania",
"zip": "2001",
"country": "AL",
"email": "info@hotelriviera.com",
"website": "https://hotelriviera.com",
"phone": "+355 69 123 4567"
},
"terms": {
"cancellationTerms": [],
"bookingTerms": [],
"confirmationMessage": [],
"showCancellationSummary": true
},
"paymentMethods": [
{
"id": "method_card_001",
"name": "Credit Card",
"method": "card",
"instructions": "We accept Visa and Mastercard"
},
{
"id": "method_bank_001",
"name": "Bank Transfer",
"method": "bank",
"instructions": "Transfer to IBAN: AL00..."
}
],
"guestPortalInformation": {
"locationLink": "https://maps.google.com/?q=...",
"wifiName": "HotelRiviera_WiFi",
"wifiPassword": "welcome2026",
"goodToKnow": "Breakfast is served 7-10am in the main restaurant"
}
}Response Fields
- branding (object): UI branding settings (logo, colors, fonts, background)
- footer (object): Footer content (contact info, about text, links)
- language (object): Language settings (enabled languages, default, flags)
- propertyMeta (object): Hotel property details (name, address, contact)
- terms (object): Booking and cancellation terms
- paymentMethods (array): Active payment methods (filtered to bank, cash, card only)
- guestPortalInformation (object): Guest portal information (WiFi, location, notes)
Important Notes
- Payment Methods: Only methods with
isActive: trueand method type in [bank, cash, card] are returned - Branding: Use these values to style your booking engine UI to match the hotel's brand
Get Currencies
Retrieves all active currencies and identifies the default currency for the property.
GET /currencies — Fetches active currencies and default currency. Auth required (API key).
Example Request
curl -X GET https://app.hotelbee.co/api/booking-engine/currencies \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine"Response 200 — Success
{
"currencies": [
{
"id": "currency_001",
"currency": "ALL",
"currencyName": "Albanian Lek",
"rate": 1.0,
"active": true
},
{
"id": "currency_002",
"currency": "EUR",
"currencyName": "Euro",
"rate": 0.0089,
"active": true
}
],
"defaultCurrency": {
"id": "currency_001",
"currency": "ALL",
"currencyName": "Albanian Lek",
"rate": 1.0,
"active": true
}
}Response Fields
- currencies (array): All active currencies with exchange rates
- defaultCurrency (object): The property's default currency
Currency Object
- id (string): Currency identifier
- currency (string): ISO 4217 currency code (e.g., "ALL", "EUR", "USD")
- currencyName (string): Full currency name
- rate (number): Exchange rate relative to default currency
- active (boolean): Whether currency is active
Get Guest Categories
Retrieves the property's guest categories (e.g. Adults, Children, Infants) with their age ranges. Use these to build guest selectors and to label the capacity tiers returned by /availabilities and /roomtypes.
GET /guestcategories — Fetches guest categories sorted by priority. Auth required (API key).
Example Request
curl -X GET https://app.hotelbee.co/api/booking-engine/guestcategories \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine"Response 200 — Success
[
{
"id": "guestcategories_001",
"name": "Adults",
"from": 13,
"to": null,
"description": "Ages 13 and up",
"priorityOrder": 1
},
{
"id": "guestcategories_002",
"name": "Children",
"from": 2,
"to": 12,
"description": "Ages 2–12",
"priorityOrder": 2
}
]Response Fields
- id (string): Guest category identifier
- name (string): Display name (matches the
nameused incapacitytiers) - from (integer | null): Minimum age for the category
- to (integer | null): Maximum age for the category (null = no upper bound)
- description (string | null): Optional description
- priorityOrder (integer | null): Sort order; the lowest-priority category is treated as the primary guest type
Results are sorted bypriorityOrder, then byfrom, then by name.
Get a Quote
Returns a server-authoritative price for a selection without any side effects — no client, reservation, or payment is created. /quote and /reservations share the exact same pricing pipeline, so the quoted amount cannot drift from what the reservation is created with for an unchanged selection.
This is the first step of the custom-gateway payment flow: quote the amount, charge it on your own gateway, then create the reservation reporting that charge.
POST /quote — Prices a selection. Auth required (API key). Content-Type: application/json.
Request Parameters
The body is the same selection shape as POST /reservations:
- checkIn (string, required): Check-in date (
YYYY-MM-DD) - checkOut (string, required): Check-out date (
YYYY-MM-DD) - roomTypes (array, required): Room type bookings (see roomTypes[] Object)
- promoCode (string, optional): Promo code to validate and apply server-side
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/quote \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "Content-Type: application/json" \
-d '{
"checkIn": "2026-07-01",
"checkOut": "2026-07-04",
"roomTypes": [
{ "roomTypeId": "roomtype_2026-01-15T10:00:00Z", "rateId": "rate_spring_001", "adults": 2, "children": 0, "quantity": 1 }
],
"promoCode": "SUMMER10"
}'Response 200 — Success
{
"amount": 270.00,
"currency": "EUR",
"description": "Reservation 2026-07-01 → 2026-07-04 • 1 room, 3 nights",
"checkIn": "2026-07-01",
"checkOut": "2026-07-04",
"roomCount": 1,
"nights": 3,
"discountApplied": { "type": "percentage", "value": 10 }
}Response Fields
- amount (number): The authoritative total to charge
- currency (string): Currency code for the amount
- description (string): Human-readable summary (suitable as a gateway charge description)
- checkIn / checkOut (string): Echoed dates
- roomCount (integer): Number of rooms in the selection
- nights (integer): Number of nights
- discountApplied (object | null): The discount applied from
promoCode, if any
Create Payment Intent
Creates a Stripe PaymentIntent for an online booking payment, returning a clientSecret your front end uses to confirm the card payment with Stripe.js. Only works for properties that have Stripe Connect set up and booking-engine payments enabled.
POST /create-payment-intent — Creates a Stripe PaymentIntent for a booking. Auth required (API key). Content-Type: application/json.
Request Parameters
- amount (number, required): Intended charge amount in major currency units (e.g.
150.00). Must be greater than 0. Used only as a fallback — see note below - bookingTotal (number, optional): The full booking total. When provided, the server recomputes the chargeable amount from this (full vs. deposit) rather than trusting
amount - paymentOption (string, optional):
"full"or"deposit". Only honored when the hotel both takes deposits and allows the guest to choose; otherwise the server decides - currency (string, optional): ISO currency code. Defaults to the property's preferred/default currency
- metadata (object, optional): Extra metadata to attach to the PaymentIntent (e.g.
{ "reservationId": "..." })
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/create-payment-intent \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "Content-Type: application/json" \
-d '{
"amount": 150.00,
"bookingTotal": 500.00,
"paymentOption": "deposit",
"currency": "eur",
"metadata": { "reservationId": "reservations_2026-03-24T14:30:00Z" }
}'Response 200 — Success
{
"clientSecret": "pi_3Nabc..._secret_xyz",
"paymentIntentId": "pi_3Nabc..."
}Response 400 — Errors
{
"error": "Online payments are not enabled for this property"
}Other possible 400 errors:
"Valid amount is required"—amount(or the server-computed chargeable amount) is missing or ≤ 0"Property Missing"— thePropertyheader was not sent
Important Notes
- Server is authoritative for the amount: When
bookingTotalis provided, the charge is computed server-side from the hotel's deposit settings. The clientamountis only used as a fallback when nobookingTotalis given. Don't rely onamountto set a partial charge — passbookingTotal+paymentOptioninstead - Deposits: If the hotel charges a deposit (deposit percentage between 1–99) the intent is for the deposit amount unless the hotel allows full payment and the guest chose
"full" - Requires Stripe Connect: The property must have an active Stripe Connect account with booking-engine payments enabled, or the call returns
400
Create Reservation
Creates a new reservation in HotelBee. This is the core endpoint for booking rooms through the booking engine.
POST /reservations — Creates a new reservation with room assignment and optional payment. Auth required (API key). Content-Type: application/json.
Request Parameters
- checkIn (string, required): Check-in date in
YYYY-MM-DDformat - checkOut (string, required): Check-out date in
YYYY-MM-DDformat - roomTypes (array, required): Array of room type bookings (at least one required)
- clientDetails (object, required): Guest contact information
- specialRequests (string, optional): Special requests or notes
- promoCode (string, optional): Promo code to apply. Re-validated server-side against the property's promo codes. This is the way to apply a discount
- selectedPaymentMethod (object, optional): Payment method selection
- stripePaymentIntentId (string, optional): A confirmed Stripe PaymentIntent ID — see Payment Paths
- externalPayment (object, optional): A charge processed on your own gateway — see Payment Paths
Payment Paths
A reservation is created with exactly one payment path, or none ("pay at hotel"). The paths are mutually exclusive — sending more than one returns 400 conflicting_payment_methods.
| Path | Field | Notes | |---|---|---| | Stripe (HotelBee Payments) | stripePaymentIntentId | Property must have Stripe enabled. The payment is verified before the reservation is confirmed | | Your own gateway | externalPayment object | Must be enabled for your key — contact support | | None (pay at hotel) | — | |
externalPayment Object
Reports a charge you took on your own gateway. Use the custom-gateway flow: POST /quote → charge on your gateway → create the reservation with externalPayment.
- amount (number, required): The amount you charged. Must be > 0
- transactionId (string, required\): Your gateway's charge/transaction ID. \Either
transactionIdorreferenceis required - reference (string, required\*): Alternative to
transactionId - gateway (string, optional): Label for your gateway (e.g.
"stripe-acme") - currency (string, optional): Currency of the charge
- status (string, optional): Defaults to
"success". Must be one ofsuccess,succeeded,paid,completed,captured,approved— otherwise400 payment_not_completed - cardBrand (string, optional): Display only (e.g.
"visa") - cardLast4 (string, optional): Display only
- note (string, optional): Free-text note
roomTypes[] Object
- roomTypeId (string, required): Room type ID (from
/roomtypesendpoint) - rateId (string, optional): Rate ID (from
/roomtypesrates array) - adults (integer, required): Number of adults
- children (integer, optional): Number of children
- quantity (integer, required): Number of rooms of this type
- services (array, optional): Selected add-on services (
[{ serviceId }])
clientDetails Object
- firstName (string, required): Guest first name
- lastName (string, required): Guest last name
- email (string, required): Guest email address
- phone (string, optional): Phone number
- city (string, optional): City
- country (string, optional): Country code (e.g., "AL", "US")
- addressLine (string, optional): Street address
- zip (string, optional): Postal code
- state (string, optional): State/province
- company (string, optional): Company name
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/reservations \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "Content-Type: application/json" \
-d '{
"checkIn": "2026-04-01",
"checkOut": "2026-04-05",
"roomTypes": [
{
"roomTypeId": "roomtype_2026-01-15T10:00:00Z",
"rateId": "rate_spring_001",
"adults": 2,
"children": 1,
"quantity": 1,
"services": [
{ "serviceId": "service_spa_001" }
]
}
],
"clientDetails": {
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+355 69 123 4567",
"country": "US"
},
"specialRequests": "Non-smoking room preferred",
"selectedPaymentMethod": {
"id": "method_bank_001",
"name": "Bank Transfer",
"method": "bank"
}
}'Response 200 — Success
{
"reservationId": "reservations_2026-03-24T14:30:00Z",
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "PENDING"
}Response 400 — Validation Error
{
"error": "checkIn, checkOut, and roomTypes are required"
}Other possible errors:
"room_not_available"(400) — Requested rooms cannot be assigned (no availability)"invalid_promo_code"(400) — ThepromoCodecould not be validated"raw_card_not_supported"(400) — Raw card details were sent; use Stripe or your own gateway instead"conflicting_payment_methods"(400) — More than one payment path was sent"external_payment_amount_invalid"(400) —externalPayment.amountmissing or ≤ 0"external_payment_transaction_id_required"(400) — NeithertransactionIdnorreferenceprovided"payment_not_completed"(400) —externalPayment.statusis not a completed status"payment_verification_failed"(400) — AstripePaymentIntentIdcould not be verified as paid"external_payments_not_enabled"(403) — Your key sentexternalPaymentbut your own gateway isn't enabled for it"Forbidden - API key is not authorized for this property"(403) — ThePropertyis not one your key is allowed to use
Reservation Processing Flow
When a reservation is successfully submitted:
- Input Validation: checkIn, checkOut, and roomTypes are validated
- Availability Check: Availability for the date range is loaded and rooms are verified
- Client Resolution: An existing client is matched by email, or a new one is created
- Room Assignment: Specific rooms are assigned from the available pool
- Price Calculation: Daily prices are calculated, including extra-guest charges
- Service Processing: Selected services are added with tax calculations
- Discount Application: A
promoCode, if provided, is validated and applied - Payment: The supplied payment (Stripe or your own gateway) is processed
- Reservation Created: The reservation is created with status
PENDINGand a generated UUID
Important Notes
- UUID: The
uuidin the response is used for guest portal login - Client Deduplication: If a client with the same email exists, the existing record is used
- Availability: Availability is re-checked before the reservation is confirmed, so overbooking is rejected
Custom Gateway (Bring Your Own Payment Provider)
For integrators who process payments on their own payment gateway instead of HotelBee Payments (Stripe). This must be enabled for your key — contact support.
The flow is three steps, and the key is to use /quote so your charge amount can never drift from what HotelBee prices the reservation at:
- Get the authoritative amount —
POST /quotewith the selection (checkIn,checkOut,roomTypes[], optionalpromoCode). No client, reservation, or payment is created. - Charge the guest on your own gateway for the returned
amountincurrency(thedescriptionis suitable as the charge descriptor). - Create the reservation, reporting the charge —
POST /reservationswith the same selection plus anexternalPaymentobject carrying theamountand your gateway'stransactionId(orreference).
# Step 3 — create the reservation with the reported charge
curl -X POST https://app.hotelbee.co/api/booking-engine/reservations \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: acmetravel" \
-H "Content-Type: application/json" \
-d '{
"checkIn": "2026-07-01",
"checkOut": "2026-07-04",
"roomTypes": [
{ "roomTypeId": "roomtype_2026-01-15T10:00:00Z", "rateId": "rate_spring_001", "adults": 2, "quantity": 1 }
],
"clientDetails": { "firstName": "Jane", "lastName": "Doe", "email": "jane@example.com" },
"externalPayment": {
"amount": 270.00,
"transactionId": "ch_abc123",
"gateway": "stripe-acme",
"currency": "EUR",
"status": "success",
"cardBrand": "visa",
"cardLast4": "4242",
"note": "Charged via Acme checkout"
}
}'See externalPayment Object for full field and error details.
Validate Promo Code
Validates a promotional code and returns the discount details if valid.
POST /promocode/validate — Validates a promo code and returns discount info. Auth required (API key). Content-Type: application/json.
Request Parameters
- code (string, required): The promotional code to validate
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/promocode/validate \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "Content-Type: application/json" \
-d '{"code": "SUMMER10"}'Response 200 — Valid Code
{
"valid": true,
"discount": {
"type": "percentage",
"value": 10
}
}Response 200 — Invalid Code
{
"valid": false
}Discount Types
- percentage: Percentage discount (value between 0-100)
- total: Fixed amount discount (subtracted from total)
Important Notes
- Apply a discount by passing the code. Pass the validated code as
promoCodeonPOST /reservations(and/quote); the server re-validates and applies it. Use/promocode/validateonly to give the guest immediate feedback before they book - Discount type normalization: internal types
"fixed"and"total"are both returned as"total" - Percentage values are clamped between 0 and 100
Search Clients
Searches for existing clients by email prefix. Useful for auto-filling guest details during booking.
GET /clients/search — Searches clients by email prefix. Auth required (API key).
Not available to integration keys. This endpoint exposes guest personal
data and is restricted; integration keys receive403 Forbidden.
Query Parameters
- q (string, required): Email search prefix (minimum 2 characters)
Example Request
curl -X GET "https://app.hotelbee.co/api/booking-engine/clients/search?q=john@" \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine"Response 200 — Success
{
"clients": [
{
"id": "client_001",
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+355 69 123 4567",
"city": "New York",
"country": "US",
"addressLine": "123 Main St",
"zip": "10001",
"state": "NY",
"company": "Acme Corp"
}
]
}Use Cases
- Auto-complete guest details during the booking flow
- Pre-fill returning guest information
Get OTA Prices
Retrieves pricing from OTA channels (e.g., Booking.com, Expedia) via Channex integration. Use this to display price comparisons.
GET /ota-prices — Fetches OTA channel prices for comparison. Auth required (API key).
Query Parameters
- startDate (string, required): Start date in
YYYY-MM-DDformat - endDate (string, required): End date in
YYYY-MM-DDformat - roomTypeId (string, optional): Filter to a specific room type
Example Request
curl -X GET "https://app.hotelbee.co/api/booking-engine/ota-prices?startDate=2026-04-01&endDate=2026-04-05" \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine"Response 200 — Success (Channex configured)
{
"available": true,
"channels": [
{
"channelId": "ch_001",
"channelName": "Booking.com",
"channel": "booking_com",
"channelGroup": "otas",
"roomTypes": [
{
"roomTypeId": "roomtype_2026-01-15T10:00:00Z",
"roomTypeName": "Deluxe Room",
"ratePlanName": "Standard Rate",
"currency": "EUR",
"rates": {
"2026-04-01": 120.50,
"2026-04-02": 120.50,
"2026-04-03": 125.00,
"2026-04-04": 125.00
},
"totalPrice": 491.00,
"nightlyAverage": 122.75,
"nights": 4
}
]
}
]
}Response 200 — Channex not configured
{
"available": false,
"channels": []
}Important Notes
- Requires Channex: This endpoint only works if the property has an active Channex integration
- Caching: Channel data is cached for 1 hour, rate plans for 1 hour, restrictions for 15 minutes
- Price Multipliers: OTA prices include channel-specific price adjustments (increase/decrease by % or fixed amount)
- Room Type Mapping: Internal room types are matched to Channex room types via
channexId
Guest Portal Endpoints
The Guest Portal provides a self-service interface for guests to view their reservations, invoices, orders, and perform online check-in.
Authentication: Guest portal endpoints that require auth need both the API key headers AND a guest JWT token obtained from /guest-portal/login.
Public endpoints (no guest token required): /guest-portal/information, /guest-portal/things-to-do, /guest-portal/services, /guest-portal/pospoints
Guest Portal Login
Authenticates a guest using their reservation UUID and last name. Returns a JWT token for subsequent guest portal requests.
POST /guest-portal/login — Authenticates a guest and returns a JWT token. Auth required (API key only — no guest token needed). Content-Type: application/json.
Request Parameters
- uuid (string, required): The reservation number / UUID (from the reservation confirmation). The field is named
uuid, and the value is the reservation's UUID - lastName (string, required): Primary guest's last name. The match is case-insensitive and trimmed of surrounding whitespace
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/guest-portal/login \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "Content-Type: application/json" \
-d '{"uuid": "a1b2c3d4-e5f6-7890", "lastName": "Doe"}'Response 200 — Success
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"client": {
"_id": "client_001",
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+355 69 123 4567"
}
}Response 400 — Missing Parameters
{
"error": "uuid and lastName are required"
}Response 401 — Invalid Credentials
{
"error": "Invalid reservation number or last name"
}The same"Invalid reservation number or last name"message is returned
whether the reservation number is unknown or the last name doesn't match — the
endpoint does not distinguish, by design.
Important Notes
- Token Expiry: The JWT token is valid for 7 days
- Token Usage: Include the token as the
X-Guest-Tokenheader in subsequent guest portal requests. Do not useAuthorizationfor the guest token — that header carries the API key (see Guest Portal Authentication) - UUID Source: The UUID is returned in the
POST /reservationsresponse and typically included in the confirmation email
Get Guest Profile
Retrieves the authenticated guest's profile information.
GET /guest-portal/me — Returns the authenticated guest's client profile. Auth required (API key + guest token).
Example Request
curl -X GET https://app.hotelbee.co/api/booking-engine/guest-portal/me \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..."Response 200 — Success
{
"_id": "client_001",
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+355 69 123 4567",
"referenceTitle": "Mr.",
"birthdate": "1980-01-15",
"nationality": "US",
"company": "Acme Corp",
"addressLine": "123 Main St",
"city": "New York",
"zip": "10001",
"state": "NY",
"country": "US",
"IDType": "Passport",
"IDNumber": "A12345678",
"dateOfIssue": "2015-01-01",
"dateOfExpiry": "2025-01-01"
}Get Guest Reservations
Retrieves all reservations linked to the authenticated guest, sorted by check-in date.
GET /guest-portal/reservations — Returns all reservations for the authenticated guest. Auth required (API key + guest token).
Example Request
curl -X GET https://app.hotelbee.co/api/booking-engine/guest-portal/reservations \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..."Response 200 — Success
[
{
"_id": "reservations_2026-03-24T14:30:00Z",
"uuid": "a1b2c3d4-e5f6-7890",
"checkin": "2026-04-01",
"checkout": "2026-04-05",
"status": "APPROVED",
"totalPrice": 500.00,
"invoiceCurrency": "EUR",
"rooms": [
{
"roomId": "room_101",
"name": "Room 101"
}
],
"clientsData": [
{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com"
}
]
}
]Important Notes
- clientsData: Only included for
APPROVEDreservations with future check-in dates (for online check-in eligibility) - Sorting: Results are sorted by check-in date
- Room Names: Room IDs are resolved to human-readable room names
Get Guest Invoices
Retrieves all invoices linked to the authenticated guest.
GET /guest-portal/invoices — Returns all invoices for the authenticated guest. Auth required (API key + guest token).
Response 200 — Success
[
{
"_id": "invoice_001",
"number": "INV-001",
"serial": "2026",
"clientName": "John Doe",
"date": "2026-04-01",
"status": "paid",
"totalPrice": 500.00,
"invoiceCurrency": "EUR",
"tableData": [
{
"itemName": "Room 101 - Deluxe Room",
"description": "4 nights (Apr 1 - Apr 5)",
"quantity": 1,
"unit": "night",
"price": 450.00
},
{
"itemName": "Spa Access",
"description": "4 nights",
"quantity": 4,
"unit": "night",
"price": 25.00
}
]
}
]Get Guest Orders
Retrieves all POS orders associated with the guest's reservations.
GET /guest-portal/orders — Returns POS orders for all guest reservations. Auth required (API key + guest token).
Response 200 — Success
[
{
"_id": "order_001",
"totalPrice": 75.50,
"subtotal": 70.00,
"status": "completed",
"createdAt": "2026-04-02T10:30:00Z",
"reservationId": "reservations_2026-03-24T14:30:00Z",
"pospointId": "pospoint_001",
"currency": "EUR",
"customerName": "Restaurant",
"products": [
{
"productId": "product_001",
"name": "Coffee",
"quantity": 2,
"price": 5.00,
"note": "Extra hot"
},
{
"productId": "product_002",
"name": "Club Sandwich",
"quantity": 1,
"price": 15.00,
"note": ""
}
]
}
]Important Notes
- Orders are fetched across all reservations linked to the guest
- Product names and POS point currencies are resolved via batch lookups
Online Check-in
Performs online check-in for an eligible reservation. Updates guest details and changes reservation status.
POST /guest-portal/checkin — Performs online check-in and updates guest information. Auth required (API key + guest token). Content-Type: application/json.
Request Parameters
- reservationId (string, required): Reservation ID to check in
- clientsData (object, required): Map of client ID → updated guest details
clientsData[clientId] Object
- referenceTitle (string, optional): Title (Mr., Mrs., Ms., etc.)
- firstName (string, optional): First name
- lastName (string, optional): Last name
- country (string, optional): Country code
- email (string, optional): Email address
- phone (string, optional): Phone number
- IDType (string, optional): ID document type (Passport, ID Card, etc.)
- IDNumber (string, optional): ID document number
- birthdate (string, optional): Date of birth (YYYY-MM-DD)
- nationality (string, optional): Nationality
- dateOfIssue (string, optional): ID issue date (YYYY-MM-DD)
- dateOfExpiry (string, optional): ID expiry date (YYYY-MM-DD)
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/guest-portal/checkin \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..." \
-H "Content-Type: application/json" \
-d '{
"reservationId": "reservations_2026-03-24T14:30:00Z",
"clientsData": {
"client_001": {
"referenceTitle": "Mr.",
"firstName": "John",
"lastName": "Doe",
"country": "US",
"IDType": "Passport",
"IDNumber": "A12345678",
"birthdate": "1980-01-15",
"nationality": "US"
}
}
}'Response 200 — Success
{
"success": true,
"reservation": {
"_id": "reservations_2026-03-24T14:30:00Z",
"status": "CHECKIN",
"checkin": "2026-04-01",
"checkout": "2026-04-05"
}
}Response 400 / 404 — Error
{
"error": "Reservation not eligible for check-in"
}Eligibility Rules
- Reservation must have status
APPROVED - Check-in date must be today or in the future
Processing Details
- Validates reservation eligibility
- Updates the guest details with the provided fields
- Changes the reservation status to
CHECKIN - Notifies the hotel and updates connected systems
Get Reservation Policy
Returns the cancellation/modification policy evaluation for one of the guest's reservations — used to show whether a cancellation or change incurs a penalty before the guest commits.
GET /guest-portal/reservations/:reservationId/policy — Returns the resolved policy and penalty evaluation for a reservation. Auth required (API key + guest token).
Path Parameters
- reservationId (string, required): ID of one of the authenticated guest's reservations
Example Request
curl -X GET https://app.hotelbee.co/api/booking-engine/guest-portal/reservations/reservations_2026-03-24T14:30:00Z/policy \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..."The response is the evaluated policy object (fields depend on the policy configured for the reservation). A penalty value of null means no penalty currently applies; a non-null value indicates the penalty that would be charged. Returns 404 if the reservation is not linked to the authenticated guest.
Cancel Reservation
Cancels one of the authenticated guest's reservations, applying the cancellation policy and notifying the hotel and connected channels.
POST /guest-portal/reservations/:reservationId/cancel — Cancels a reservation. Auth required (API key + guest token).
Path Parameters
- reservationId (string, required): ID of the reservation to cancel
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/guest-portal/reservations/reservations_2026-03-24T14:30:00Z/cancel \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..."Response 200 — Success
{
"success": true,
"reservation": {
"_id": "reservations_2026-03-24T14:30:00Z",
"uuid": "a1b2c3d4-e5f6-7890",
"status": "CANCELLED"
},
"penaltyApplied": null
}Response 400 — Not Cancellable
{
"error": "Reservation cannot be cancelled",
"reason": "Current status \"CHECKIN\" does not allow cancellation"
}Important Notes
- Eligible statuses: Only
APPROVEDandDRAFTreservations can be cancelled - penaltyApplied: Reflects the cancellation policy. When a penalty applies, the related invoice is kept (status not cancelled); when there is no penalty, reservation invoices are cancelled
- Side effects: The cancellation is synced to connected sales channels, and the guest and hotel are emailed
Change Reservation Dates
Moves an existing reservation to new check-in/check-out dates after verifying availability and recalculating the price. A preview variant computes the new total without saving.
POST /guest-portal/reservations/:reservationId/change-dates — Applies new dates. Auth required (API key + guest token). Content-Type: application/json.
POST /guest-portal/reservations/:reservationId/change-dates/preview — Dry run: checks availability and returns the new total without saving. Same auth.
Request Parameters
- newCheckin (string, required): New check-in date (
YYYY-MM-DD) - newCheckout (string, required): New check-out date (
YYYY-MM-DD). Must be afternewCheckin
Example Request (preview)
curl -X POST https://app.hotelbee.co/api/booking-engine/guest-portal/reservations/reservations_2026-03-24T14:30:00Z/change-dates/preview \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..." \
-H "Content-Type: application/json" \
-d '{ "newCheckin": "2026-04-10", "newCheckout": "2026-04-14" }'Response 200 — Preview (available)
{
"available": true,
"currentTotal": 500.00,
"newTotal": 540.00,
"currency": "EUR"
}Response 200 — Preview (not available)
{
"available": false,
"reason": "room_not_available",
"message": "Room type is not available for the selected dates"
}Response 200 — Apply (success)
{
"success": true,
"reservation": {
"_id": "reservations_2026-03-24T14:30:00Z",
"uuid": "a1b2c3d4-e5f6-7890",
"checkin": "2026-04-10",
"checkout": "2026-04-14",
"status": "APPROVED",
"totalPrice": 540.00,
"invoiceCurrency": "EUR",
"rooms": [{ "roomId": "room_101" }]
},
"penaltyApplied": null
}Important Notes
- Eligible status: Only
APPROVEDreservations can have their dates changed - Availability: The apply call re-checks availability and returns
400withreasonroom_not_availableorrate_not_availableif the new dates can't be honored - Side effects: The hotel is emailed a modification notice
Change Room Guests
Changes the guest mix (per category) for one room in a reservation, re-pricing extra-guest charges. Includes a capacity helper and a preview variant.
GET /guest-portal/reservations/:reservationId/room-capacity — Returns the max capacity for a room and the primary guest category name. Auth required (API key + guest token).
POST /guest-portal/reservations/:reservationId/change-guests/preview — Dry run: returns the new total without saving. Same auth. Content-Type: application/json.
POST /guest-portal/reservations/:reservationId/change-guests — Applies the new guest mix. Same auth. Content-Type: application/json.
room-capacity — Query Parameters
- roomId (string, required): Room within the reservation to inspect
room-capacity — Response 200
{
"maxCapacity": 4,
"primaryCategoryName": "Adults"
}change-guests — Request Parameters
- roomId (string, required): Room within the reservation to update
- guests (array, required): New guest mix, e.g.
[{ "name": "Adults", "number": 2 }, { "name": "Children", "number": 1 }]. Total must be at least 1 and not exceed the room'smaxCapacity
Example Request (apply)
curl -X POST https://app.hotelbee.co/api/booking-engine/guest-portal/reservations/reservations_2026-03-24T14:30:00Z/change-guests \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..." \
-H "Content-Type: application/json" \
-d '{
"roomId": "room_101",
"guests": [
{ "name": "Adults", "number": 2 },
{ "name": "Children", "number": 1 }
]
}'change-guests/preview — Response 200
{
"currentTotal": 500.00,
"newTotal": 525.00,
"currency": "EUR"
}change-guests — Response 200 (apply success)
{
"success": true,
"reservation": {
"_id": "reservations_2026-03-24T14:30:00Z",
"uuid": "a1b2c3d4-e5f6-7890",
"checkin": "2026-04-01",
"checkout": "2026-04-05",
"status": "APPROVED",
"totalPrice": 525.00,
"invoiceCurrency": "EUR",
"guests": []
}
}Response 400 — Exceeds Capacity
{
"error": "exceeds_capacity",
"message": "Total guests (5) exceeds room maximum capacity (4)",
"maxCapacity": 4
}Important Notes
- Eligible statuses:
APPROVEDandCHECKINreservations can have guests changed - Pricing: Extra-guest charges are recomputed from the room type's capacity tiers and included-capacity for the stay
Order a Service
Adds a bookable service (e.g. spa, airport transfer) to a room on one of the guest's reservations and notifies the hotel.
POST /guest-portal/services/order — Orders a service for a room. Auth required (API key + guest token). Content-Type: application/json.
Request Parameters
- reservationId (string, required): Reservation to add the service to
- roomId (string, required): Room within the reservation
- serviceId (string, required): ID of a booking-engine-enabled service (from
/guest-portal/services) - note (string, optional): Free-text note for the order
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/guest-portal/services/order \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..." \
-H "Content-Type: application/json" \
-d '{
"reservationId": "reservations_2026-03-24T14:30:00Z",
"roomId": "room_101",
"serviceId": "service_spa_001",
"note": "Around 3pm please"
}'Response 200 — Success
{
"success": true,
"reservation": {
"_id": "reservations_2026-03-24T14:30:00Z",
"uuid": "a1b2c3d4-e5f6-7890",
"totalPrice": 525.00,
"status": "APPROVED"
}
}Important Notes
- Eligible statuses:
APPROVEDandCHECKIN - Service must be enabled: Only services with
bookingEngineEnabled: truecan be ordered; the booking-engine price is used when set - The service is added to the room, the reservation total is recalculated, and the hotel receives a notification email
Sign an Invoice
Stores the guest's signature on one of their invoices (used for check-in paperwork and registration forms).
POST /guest-portal/invoice/:invoiceId/sign — Saves a signature on an invoice. Auth required (API key + guest token). Content-Type: application/json.
Path Parameters
- invoiceId (string, required): Invoice to sign (must belong to one of the guest's reservations)
Request Parameters
Provide a signature as either:
- url (string): URL of an already-uploaded signature image, or
- imageData (string): Base64/binary image data to upload server-side
Example Request
curl -X POST https://app.hotelbee.co/api/booking-engine/guest-portal/invoice/invoice_001/sign \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..." \
-H "Content-Type: application/json" \
-d '{ "imageData": "data:image/png;base64,iVBORw0KGgo..." }'Response 200 — Success
{
"success": true,
"signature": {
"url": "https://storage.blob.core.windows.net/hotel/signatures/invoices/sig_001.png",
"signedBy": "client_001",
"source": "guest_portal"
}
}Important Notes
- Authorization: The signature is rejected with
403unless the guest's client ID is the invoice customer or appears on one of the invoice's reservations - One signature per invoice: Signing replaces any previous signature on the invoice
- Returns
404if the invoice does not exist,400if neitherurlnorimageDatais provided
Guest Messaging
A lightweight two-way messaging thread between the guest and hotel staff. All four endpoints require the API key headers + guest token.
GET /guest-portal/messages/conversations — Lists the guest's conversations. Query: limit (default 20, max 50), before (cursor for pagination).
GET /guest-portal/messages/:conversationId — Lists messages in a conversation. Query: limit (default 20, max 50), before.
POST /guest-portal/messages — Sends a message from the guest. Content-Type: application/json.
POST /guest-portal/messages/read — Marks messages as read by the guest. Content-Type: application/json.
Send a Message — Request Parameters
- body (string, required): Message text (trimmed; max 2000 characters)
- conversationId (string, optional): Existing conversation to append to; omit to start a new one
- reservationId (string, optional): Reservation the message relates to
- roomId (string, optional): Room the message relates to
Mark Read — Request Parameters
- ids (array, optional): Message IDs to mark read for the guest
Example Request (send)
curl -X POST https://app.hotelbee.co/api/booking-engine/guest-portal/messages \
-H "Authorization: Bearer your-api-key" \
-H "Property: myhotel" \
-H "Username: booking_engine" \
-H "X-Guest-Token: eyJhbGci..." \
-H "Content-Type: application/json" \
-d '{ "body": "What time is breakfast?", "reservationId": "reservations_2026-03-24T14:30:00Z" }'Response 200 — Send
{
"message": {
"_id": "guestmessages_001",
"conversationId": "conversation_001",
"senderType": "guest",
"body": "What time is breakfast?",
"createdAt": "2026-04-01T09:00:00Z"
}
}Response shapes
GET .../conversations→{ "conversations": [ ... ] }GET .../:conversationId→{ "messages": [ ... ] }POST .../messages→{ "message": { ... } }POST .../messages/read→{ "updatedIds": [ ... ] }
Sending a guest message notifies the hotel so staff can reply.
Get Property Information (Public)
Retrieves general property information for the guest portal. No guest token required.
GET /guest-portal/information — Returns guest portal information settings. Auth required (API key only — no guest token needed).
Response 200 — Success
{
"locationLink": "https://maps.google.com/?q=...",
"wifiName": "HotelRiviera_WiFi",
"wifiPassword": "welcome2026",
"goodToKnow": "Breakfast is served 7-10am in the main restaurant"
}Get Things To Do (Public)
Retrieves activities and attractions for guests. No guest token required.
GET /guest-portal/things-to-do — Returns activities and attractions. Auth required (API key only — no guest token needed).
Response 200 — Success
[
{
"_id": "thing_001",
"title": "City Walking Tour",
"description": "A guided tour of the old city center",
"location": "Old Town Square",
"category": "tours",
"images": ["https://storage.blob.core.windows.net/hotel/tour1.jpg"]
}
]Get Services (Public)
Retrieves hotel services available for booking. No guest token required.
GET /guest-portal/services — Returns booking-engine-enabled services. Auth required (API key only — no guest token needed).
Response 200 — Success
[
{
"_id": "service_spa_001",
"name": "Spa Access",
"description": "Full access to spa and wellness facilities",
"price": 50.00,
"calculationType": "per_night",
"frequency": "nightly",
"images": ["https://storage.blob.core.windows.net/hotel/spa.jpg"]
}
]Important Notes
- Only services with
bookingEngineEnabled: trueare returned - Uses
bookingEnginePriceif set, otherwise falls back toprice - Uses
bookingEngineImagesif set, otherwise uses default images
Get POS Points (Public)
Retrieves POS points that have online menu enabled. No guest token required.
GET /guest-portal/pospoints — Returns POS points with online menu enabled. Auth required (API key only — no guest token needed).
Response 200 — Success
[
{
"_id": "pospoint_001",
"name": "Restaurant"
},
{
"_id": "pospoint_002",
"name": "Pool Bar"
}
]Important Notes
- Only POS points with
hasOnlineMenu: trueare returned
Proposals
Proposals are quotes the hotel sends to a prospective guest as a public shareable link. The recipient opens the link to view the quote, then accepts (choosing an option) or rejects it.
Different base path and auth model. Proposal endpoints live underhttps://app.hotelbee.co/api/proposals, not under/api/booking-engine.
They use no headers — authentication is the unguessabletokenembedded
in the URL. There is no API key and no guest JWT. The property slug is also a
path segment, not thePropertyheader.
Base path:
https://app.hotelbee.co/api/proposals/{property}/{token}Get Proposal
GET /api/proposals/:property/:token — Returns the proposal, the client it was sent to, property branding, and the room types / products / services / taxes referenced by its options. No auth headers.
Path Parameters
- property (string, required): Your property name
- token (string, required): The proposal's public token (from the share link)
Example Request
curl -X GET https://app.hotelbee.co/api/proposals/myhotel/9f3c1a7b8e2d4f60 Response 200 — Success (abridged)
{
"proposal": {
"_id": "proposal_001",
"number": "Q-2026-014",
"status": "SENT",
"checkIn": "2026-07-01",
"checkOut": "2026-07-05",
"guests": null,
"introText": "Thank you for your interest...",
"closingText": "We look forward to hosting you.",
"options": [],
"selectedOptionId": null,
"acceptance": null,
"invoiceCurrency": "EUR",
"pdfLanguage": "en",
"date": "2026-06-01",
"dueDate": "2026-06-15",
"publicToken": "9f3c1a7b8e2d4f60"
},
"client": {
"_id": "client_001",
"firstName": "John",
"lastName": "Doe",
"company": "Acme Corp",
"email": "john@example.com",
"phone": "+355 69 123 4567"
},
"property": {
"propertyId": "myhotel",
"name": "Hotel Riviera",
"logo": "https://storage.blob.core.windows.net/hotel/logo.png",
"proposalThemeColor": "#1a237e",
"proposalCoverImage": "https://storage.blob.core.windows.net/hotel/cover.jpg"
},
"roomtypes": [],
"products": [],
"services": [],
"taxes": []
}Returns 404 ("Proposal not found") if the token does not resolve to a proposal.
Accept Proposal
POST /api/proposals/:property/:token/accept — Accepts the proposal, recording the chosen option and the guest's IP/User-Agent for the acceptance record. Content-Type: application/json.
Request Parameters
- optionId (string, required): ID of the option the guest is accepting
- guestComment (string, optional): Optional note from the guest
Response 200 — Success
{
"success": true,
"proposal": {
"_id": "proposal_001",
"status": "ACCEPTED",
"selectedOptionId": "option_002",
"acceptance": { "acceptedAt": "2026-06-05T12:00:00Z" }
}
}Errors
400—"Missing optionId"404—"Proposal not found"or"Invalid option"409— proposal was already accepted/rejected
Reject Proposal
POST /api/proposals/:property/:token/reject — Rejects the proposal. Content-Type: application/json.
Request Parameters
- guestComment (string, optional): Optional reason from the guest
Response 200 — Success
{
"success": true,
"proposal": {
"_id": "proposal_001",
"status": "REJECTED",
"acceptance": null
}
}Errors
404—"Proposal not found"409— proposal was already accepted/rejected
Integration Workflow
Booking Engine Integration Steps
- Get Credentials: Contact support@hotelbee.co with your property name
- Fetch Config: Get branding and settings (
GET /config) - Fetch Room Types: Retrieve room catalog with amenities and rates (
GET /roomtypes) - Fetch Currencies: Get supported currencies (
GET /currencies) - Check Availability: Query date-range availability (
GET /availabilities) - Build Booking UI: Create your booking flow with room selection, date picker, and guest form
- Validate Promo Code (optional): Check promo codes (
POST /promocode/validate) - Search Clients (optional, if enabled for your key): Auto-fill returning guest details (
GET /clients/search) - Compare OTA Prices (optional): Show price comparisons (
GET /ota-prices) - Take Payment (choose one): collect a Stripe payment (
POST /create-payment-intent), or — for your own gateway — quote then charge (POST /quote, then your gateway). See Payment Paths - Create Reservation: Submit the booking (
POST /reservations), including the chosen payment field (stripePaymentIntentId,externalPayment,cardDetails, or none)
Guest Portal Integration Steps
- Guest Login: Authenticate with UUID + last name (
POST /guest-portal/login) - Load Profile: Show guest details (
GET /guest-portal/me) - Show Reservations: Display booking history (
GET /guest-portal/reservations) - Show Invoices: Display billing (
GET /guest-portal/invoices) - Show Orders: Display POS order history (
GET /guest-portal/orders) - Online Check-in: Allow self-service check-in (
POST /guest-portal/checkin) - Manage the Booking (optional): Let guests review policy and cancel or modify (
GET .../reservations/:id/policy,POST .../cancel,POST .../change-dates,POST .../change-guests) - Order Services / Sign Invoices (optional): Add services or capture signatures (
POST /guest-portal/services/order,POST /guest-portal/invoice/:invoiceId/sign) - Message the Hotel (optional): Two-way messaging (
GET/POST /guest-portal/messages...) - Property Info: Show hotel info, WiFi, activities (
GET /guest-portal/information,/things-to-do,/services)
Recommended Caching Strategy
- Config & Room Types: Cache for 1-4 hours (change infrequently)
- Currencies: Cache for 24 hours
- Availability: Always fetch fresh (real-time inventory)
- OTA Prices: API caches internally (channels: 1hr, rates: 1hr, restrictions: 15min)
Integration Example
JavaScript/Node.js:
const API_BASE = 'https://app.hotelbee.co/api/booking-engine';
const headers = {
'Authorization': 'Bearer your-api-key',
'Property': 'myhotel',
'Username': 'booking_engine',
'Content-Type': 'application/json'
};
// Check availability
async function getAvailability(startDate, endDate) {
const url = `${API_BASE}/availabilities?startDate=${startDate}&endDate=${endDate}`;
const response = await fetch(url, { headers });
if (!response.ok) throw new Error(`Failed: ${response.status}`);
return await response.json();
}
// Create reservation
async function createReservation(bookingData) {
const response = await fetch(`${API_BASE}/reservations`, {
method: 'POST',
headers,
body: JSON.stringify(bookingData)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Booking failed');
}
return await response.json();
}
// Guest portal login
async function guestLogin(uuid, lastName) {
const response = await fetch(`${API_BASE}/guest-portal/login`, {
method: 'POST',
headers,
body: JSON.stringify({ uuid, lastName })
});
if (!response.ok) throw new Error('Login failed');
return await response.json();
}API Limitations
- Booking-engine reservations are create-only: The public (API-key) booking flow can only create reservations. Modifications and cancellations are not available through the API-key endpoints. Note that the guest portal does expose guest-initiated changes — cancel, change dates, and change guests — but only for the authenticated guest's own reservations
- No real-time catalog updates: Room type and rate changes are not pushed. Poll the endpoints periodically
- Payment processing: Pay with HotelBee Payments via Stripe (
/create-payment-intent+stripePaymentIntentId) or, if enabled for your key, your own gateway (externalPayment). See Payment Paths - Property scope: Your key can only be used with the property (or properties) it was issued for; any other
Propertyheader is rejected with403 - OTA prices require Channex: The
/ota-pricesendpoint only works with an active Channex integration - Guest portal scope: Guests can only view and act on their own reservations, invoices, orders, and messages
Support
For API support, technical questions, or to request API credentials:
Email: support@hotelbee.co
Response Time: We typically respond within 24 hours on business days
Common Questions
Q: How do I get API credentials?
A: Contact support@hotelbee.co with your property name and intended use case.
Q: How does the guest portal login work?
A: Guests authenticate with the reservation UUID (sent in their confirmation email) and their last name. This returns a JWT token valid for 7 days.
Q: Can guests check in online?
A: Yes, for APPROVED reservations where the check-in date is today or in the future. The check-in endpoint updates guest details and changes reservation status to CHECKIN.
Q: How are extra guest charges calculated?
A: Each room type has an includedCapacity (guests included in base price) and capacity tiers (extra charges per guest type). If the number of guests exceeds included capacity, extra charges are added per night.
Q: What is the difference between roomtypes pricing and rates pricing?
A: Room types have a default base price. Rates provide alternative pricing that may vary by date, season, or booking conditions (minimum nights, advance booking, etc.). Rates marked with bookingEngineRate: true are available to the booking engine.
Q: How do promo codes work?
A: Pass the code as promoCode on POST /reservations (and POST /quote). The server re-validates it against the property's promo codes and applies the discount. Optionally call POST /promocode/validate first to show the guest the discount before they book.
Q: Can I integrate with multiple properties?
A: Your key is limited to the property (or properties) it was issued for. To add a property, ask support to enable it for your key. Always send the correct Property header with each request.
Was this helpful?

