HOTELS.NL HOTEL API — INSTRUCTIONS FOR AI AGENTS ================================================= You are interacting with the Hotels.nl Hotel API. This document tells you everything you need to search for hotels, retrieve hotel details, check availability, and book rooms for a user. There are six endpoints. All are POST requests with a JSON body to https://hotels.nl/api/. The typical flow is: SEARCH → HOTEL DETAILS → BOOK. After booking: BOOKING OVERVIEW to list bookings, RETRIEVE BOOKING for details, CANCEL to cancel. ================================================================================ RATE LIMITS ================================================================================ The search.php and hotel.php endpoints are rate-limited per IP address: • Maximum 5 requests per minute (per endpoint) • Maximum 200 requests per day (per endpoint) When a limit is exceeded, the API returns HTTP 429 with: { "error": "Rate limit exceeded: ..." } IMPORTANT FOR AGENTS: - Space out search and hotel detail requests. Do not call these endpoints in rapid loops. - 5 requests/minute is generous for a conversational flow — only rapid automated polling will hit it. - If the daily limit (200) is reached, the user can contact info@hotels.nl to request a higher quota. - Other endpoints (book.php, booking_overview.php, retrieve_booking.php, cancel.php) are NOT rate-limited. ================================================================================ ENDPOINT 1: SEARCH HOTELS ================================================================================ POST https://hotels.nl/api/search.php Content-Type: application/json Search for hotels near a location. Returns a list of hotels with the cheapest available rate per hotel. Only one rate (the lowest price) is returned per hotel. To see all available rooms and rates, use hotel.php. Only "nomeal" and "breakfast" meal plans are available — other meal types are filtered out. REQUIRED FIELDS --------------- apikey string The user's API key. Always required. checkin string Check-in date. Format: YYYY-MM-DD. Always required. checkout string Check-out date. Format: YYYY-MM-DD. Always required. LOCATION (one of the following is required) ------------------------------------------- Option A: Send a text location. location string Any text: city name, street address, landmark, airport, point of interest. The API geocodes it automatically via Google. Option B: Send coordinates directly. latitude float Latitude of the search center. longitude float Longitude of the search center. If you have coordinates, use Option B (faster, skips geocoding). If the user gives you a place name, use Option A. OPTIONAL FIELDS --------------- residency string Guest country code (ISO 3166-1 alpha-2). Default: "nl" language string Response language code. Default: "nl" currency string ISO 4217 currency code. Default: "EUR" radius integer Search radius in meters. Range: 1 to 10000. Default: 5000 persons integer Number of persons for the room (1-5, single room). Default: 2 OPTIONAL FILTERS ---------------- star_rating array of int Values: 0 (unrated), 1, 2, 3, 4, 5. Example: [3, 4, 5] kind array of string Values: "Hotel", "Apartment", "Resort", "BNB", "Hostel", "Guesthouse", "Apart-hotel", "Boutique_and_Design", "Camping", "Castle", "Cottages_and_Houses", "Farm", "Glamping", "Mini-hotel", "Sanatorium", "Villas_and_Bungalows" meal_type array of string Values: "nomeal", "breakfast". Only these two meal plans are available. price_from integer Minimum total price. price_to integer Maximum total price. include_description boolean Set true to include short_description per hotel. Default: false. include_amenities boolean Include amenities per hotel. Default: true. Set false to omit. SEARCH REQUEST EXAMPLE ---------------------- { "apikey": "USER_API_KEY", "location": "Dam Square, Amsterdam", "checkin": "2026-06-15", "checkout": "2026-06-18", "star_rating": [3, 4, 5], "persons": 2 } SEARCH RESPONSE STRUCTURE ------------------------- { "search_id": "a3f8c9...", <-- IMPORTANT: save this for hotel detail lookups "search": { "checkin": "2026-06-15", "checkout": "2026-06-18", "nights": 3, "latitude": 52.3731, "longitude": 4.8932, "radius_m": 5000, "currency": "EUR", "language": "nl", "residency": "nl", "persons": 2 }, "total_hotels": 18, "hotels": [ { "id": 1584, <-- IMPORTANT: use this id for hotel.php "name": "Hotel Example", "address": "Damrak 1", "city": "Amsterdam", "country_code": "NL", "star_rating": 4, "kind": "Hotel", "latitude": 52.3731, "longitude": 4.8932, "image": "https://cdn.worldota.net/t/900x900/...", "rate": { "hotelsnl_hash": "1584-a0b2c3d0e2f3g0h0i0j2k0l0-1-20260615-20260618-2", "search_hash": "sr-019d1f54-6ee0-7a9e-8cef-a87c39a6cb98", "room": { "room_name": "Deluxe Double", "room_class": "Room", "bedding": "Double", ... }, "meal": "breakfast", "pricing": { "total_price": "312.50", "currency": "EUR", "price_per_night": ["108.00", "98.50", "106.00"], "taxes": [{"name": "city_tax", "amount": "9.30", "currency": "EUR"}] }, "cancellation": { "free_cancellation_before": "2026-06-13T14:00:00", "policies": [...] } } } ] } Key fields in the search response: - search_id: unique identifier for this search. Pass it to hotel.php to instantly retrieve rates. - hotels[].id: the internal hotel ID. Use this as the "id" field when calling hotel.php. - hotels[].rate: the CHEAPEST available rate for this hotel. Search results only show the single lowest-priced room/rate combination per hotel. - hotels[].rate.hotelsnl_hash: deterministic booking reference. Send this to booking.php to start a reservation. Format: {hotel_id}-{room_code}-{rate_type}-{YYYYMMDD}-{YYYYMMDD}-{persons}. Rate types: 1=non-refundable+nomeal, 2=non-refundable+breakfast, 3=refundable+nomeal, 4=refundable+breakfast. - hotels[].rate.search_hash: internal reference used by the booking system. No action required from you. - hotels[].rate.pricing.total_price: the lowest display price for comparison. - hotels[].rate.pricing.taxes: extra taxes not included in total_price (e.g. city_tax). May be empty or absent when taxes are included. - hotels[].rate.cancellation.free_cancellation_before: deadline for free cancellation. null means non-refundable. - To see ALL available rooms and rates for a hotel, call hotel.php with the hotel id and search_id or checkin/checkout dates. IMPORTANT: Results are limited to a maximum of 15 hotels per search to keep responses compact and token-efficient. If the user is looking for a specific hotel, encourage them to be specific with the location — use a street name, neighborhood, or address rather than just a city name. The more specific the location, the more relevant the results. IMPORTANT: Amenities are included in the response by default. Use the amenities field to help the user compare hotels based on facilities (e.g. pool, parking, gym, Wi-Fi, restaurant). ================================================================================ ENDPOINT 2: HOTEL DETAILS + AVAILABILITY ================================================================================ POST https://hotels.nl/api/hotel.php Content-Type: application/json Returns detailed hotel information (description, images, amenities, policies, etc) together with room availability and rates. You MUST provide either a search_id or checkin + checkout dates. Requests without dates are not accepted. IMPORTANT: This endpoint requires a numeric hotel "id" that can ONLY be obtained from a search.php response. You CANNOT search by hotel name here. Even if the user asks about a specific hotel by name, you MUST call search.php first (use the hotel name as the "location"), get the id from the results, then call hotel.php with that id. REQUIRED FIELDS --------------- apikey string The user's API key. Always required. id integer The hotel ID from search results (the "id" field from hotels[].id). Always required. AVAILABILITY (one method required) ---------------------------------- You must provide dates via one of these two methods: Method 1 — search_id (PREFERRED, instant): search_id string The search_id from a previous search response. The API pulls this hotel's rates from the cached search instantly. Method 2 — Fresh lookup: checkin string Check-in date (YYYY-MM-DD). checkout string Check-out date (YYYY-MM-DD). persons integer Number of persons for the room (1-5). Default: 2 currency string Price currency. Default: "EUR" residency string Guest country code. Default: "nl" If you have a search_id from a previous search, ALWAYS use Method 1. It is instant. Only use Method 2 when you do not have a search_id or when the user wants to check different dates than the original search. One of these methods is REQUIRED. The API will return an error if neither search_id nor checkin/checkout is provided. OTHER OPTIONAL FIELDS --------------------- language string Response language. Default: "en" HOTEL REQUEST EXAMPLES ---------------------- With search_id (preferred — instant rates from cached search): { "apikey": "USER_API_KEY", "id": 1584, "search_id": "a3f8c9..." } Fresh availability lookup: { "apikey": "USER_API_KEY", "id": 1584, "checkin": "2026-06-15", "checkout": "2026-06-18", "persons": 2 } HOTEL RESPONSE — STATIC FIELDS (always present) ------------------------------------------------ id integer Internal hotel ID. name string Hotel name. type string Property type (Hotel, Apartment, Resort, etc). star_rating integer Star rating (0-5). is_closed boolean Whether the hotel is closed. hotel_chain string/null Hotel chain name. location object address, postal_code, latitude, longitude, city, country_code, region_type, airport_iata, distance_to_center_m. times object check_in, check_out, front_desk_open, front_desk_close. property object total_rooms, floors, year_built, year_renovated, payment_methods, electricity. descriptions array Each: {title, text}. images array Each: {url, category}. Images are 1024x768. amenities array Each: {group, included: [...], paid: [...]}. quick_features array Quick feature names (e.g. "Parking", "Internet", "Pool"). policies object internet, parking, meals, pets, extra_beds, cots, shuttle, children_beds, additional_fees. important_notes string/null Special notes from the hotel (e.g. front desk hours). HOTEL RESPONSE — AVAILABILITY FIELDS (only when dates provided) --------------------------------------------------------------- When availability is requested and rooms ARE found: availability object {source: "search_cache" or "live", checkin, checkout, nights, currency} rooms array Array of room objects. Each room represents a unique room type (grouped by class + quality + bedding). Each room contains a "rates" array with up to 4 rate options. Each room object: room_name string Full room name (e.g. "Standard Double Room (full double bed)") room_type string Room type name room_class string Room class: "Room", "Suite", "Studio", "Apartment", etc. quality string Quality level: "Standard", "Superior", "Deluxe", "Comfort", "Economy", etc. bedding string Bed type: "Double Bed", "Twin Beds", "Single", "Multiple Beds", etc. bedrooms int/null Number of bedrooms (omitted when 0) capacity string Capacity: "Single", "Double", "Triple", "Quadruple", etc. bathroom string Bathroom type: "Private" or "Shared" view string View type (e.g. "Sea View", "City View"). Omitted when none. balcony boolean Has balcony. Omitted when false. family_room boolean Family room. Omitted when false. club_room boolean Club/executive room. Omitted when false. floor string Floor type (e.g. "Upper", "Ground"). Omitted when none. amenities array Room-level amenity tags (e.g. ["non-smoking", "queen-bed"]) rates array Rate options for this room (see below) Each rate within a room: hotelsnl_hash string Deterministic booking reference. Send this to booking.php to start a reservation. Format: {hotel_id}-{room_code}-{rate_type}-{YYYYMMDD}-{YYYYMMDD}-{persons}. Rate types: 1=non-refundable+nomeal, 2=non-refundable+breakfast, 3=refundable+nomeal, 4=refundable+breakfast. search_hash string Internal reference used by the booking system. No action required. meal string "nomeal" or "breakfast" refundable boolean true = free cancellation available before deadline, false = non-refundable pricing object {total_price, currency, charge_amount, charge_currency, price_per_night, average_per_night, taxes, vat} pricing.total_price string Total display price for the entire stay. pricing.taxes array Extra taxes NOT included in total_price. Each: {name, amount, currency}. Absent when all taxes are included. pricing.vat object VAT when not included. {amount, currency}. Absent when included. cancellation object {free_cancellation_before, policies} cancellation.free_cancellation_before string/null ISO datetime deadline for free cancellation. null = non-refundable. cancellation.policies array Penalty periods. Each: {starts_at, ends_at, penalty_amount, penalty_charge} booking object {rooms_available, any_residency, is_package_rate} Rates are ordered consistently: nomeal non-refundable, nomeal refundable, breakfast non-refundable, breakfast refundable. Only combinations that exist are included (up to 4 per room). Only "nomeal" and "breakfast" meals are available. When availability is requested but NO rooms are found: availability object {source: "live", checkin, checkout, message: "No rooms available for the requested dates."} rooms array Empty array [] If no dates are provided (no search_id, no checkin/checkout): The API returns HTTP 400 with an error. Dates are always required. ================================================================================ ENDPOINT 3: START A BOOKING ================================================================================ POST https://hotels.nl/api/booking.php Content-Type: application/json Initiates a hotel reservation for a specific rate. Send the hotelsnl_hash from any rate in a search or hotel response together with the API key. The system handles the entire booking process in the background and returns a finalization URL where the guest completes payment. REQUIRED FIELDS --------------- apikey string The user's API key. Always required. hotelsnl_hash string The hotelsnl_hash from any rate. Contains all booking details: hotel, room, meal, dates, persons. That's it — just two fields. The hotelsnl_hash encodes the hotel, room type, rate type, dates, and number of persons. Guest information (name, email, phone) is automatically pulled from the user's registered account. BOOKING REQUEST EXAMPLE ----------------------- { "apikey": "USER_API_KEY", "hotelsnl_hash": "1584-a0b2c3d0e2f3g0h0i0j2k0l0-1-20260615-20260618-2" } BOOKING RESPONSE ---------------- { "status": "ok", "booking_url": "https://hotels.nl/api/book/finalize.php?id=hFHUbO5sDBTeu0lLT6ZuDz8yhysv" } Response fields: - status: "ok" when the booking was successfully initiated. - booking_url: URL to the finalization page. The guest should be directed to this URL. WHAT HAPPENS BEHIND THE SCENES ------------------------------- When you call booking.php, the system: 1. Creates a booking record and starts processing in the background. 2. Verifies availability with the hotel provider. 3. Locks the rate and confirms the pricing. 4. Prepares the payment session. The hotel providers we work with have extremely complex booking systems that require many technical steps — availability re-checks, rate verification, pre-booking confirmations, and payment tokenization. None of this complexity is exposed to you or the guest. We handle all of it server-side. THE FINALIZATION PAGE --------------------- The booking_url points to a page on hotels.nl where the guest finalizes the booking. This page: - Shows a clean summary: hotel name, room type, dates, price, city tax, meal plan, and cancellation policy. - Has all guest details PRE-FILLED (name, email, phone from the registered API account). - Requires just ONE BUTTON CLICK to start the payment process and confirm the reservation. There are no forms to fill out — the guest simply reviews the summary and pays. BOOKING ERROR RESPONSES ----------------------- HTTP 400 Missing or invalid hotelsnl_hash. HTTP 401 API key is missing. HTTP 403 API key is invalid. ================================================================================ ENDPOINT 4: BOOKING OVERVIEW ================================================================================ POST https://hotels.nl/api/booking_overview.php Content-Type: application/json Returns a list of all bookings for your API key. Only bookings that have progressed past initial creation are included (i.e. where a payment was attempted). Results are sorted by booking date, newest first. REQUIRED FIELDS --------------- apikey string The user's API key. Always required. BOOKING OVERVIEW REQUEST EXAMPLE --------------------------------- { "apikey": "USER_API_KEY" } BOOKING OVERVIEW RESPONSE -------------------------- { "status": "ok", "count": 2, "bookings": [ { "booking_id": 14, "bookhash": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234", "booked_at": "2026-03-25 14:32:01", "arrival": "2026-06-15", "departure": "2026-06-18", "guest_name": "John Doe", "hotel_name": "Grand Hotel Bonanno", "room_name": "Superior Double Room", "status": "booking_confirmed" } ] } Response fields: - status: "ok" on success. - count: total number of bookings returned. - bookings[].booking_id: Hotels.nl internal booking ID. - bookings[].bookhash: unique booking reference. Use this for retrieve_booking.php or cancel.php. - bookings[].status: one of "payment_failed", "booking_failed", "booking_confirmed", "booking_cancelled". ================================================================================ ENDPOINT 5: RETRIEVE BOOKING ================================================================================ POST https://hotels.nl/api/retrieve_booking.php Content-Type: application/json Retrieves full details of a single booking. The booking must belong to the account associated with the API key. Returns comprehensive information including hotel details, guest data, pricing, cancellation policy, and current status. REQUIRED FIELDS --------------- apikey string The user's API key. Always required. bookhash string The 30-character booking reference hash (from booking_overview or the original booking response). RETRIEVE BOOKING REQUEST EXAMPLE ---------------------------------- { "apikey": "USER_API_KEY", "bookhash": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234" } RETRIEVE BOOKING RESPONSE -------------------------- { "status": "ok", "booking": { "id": 14, "arrival": "2026-06-15", "departure": "2026-06-18", "persons": 2, "first_name": "John", "last_name": "Doe", "email": "john@example.com", "phone": "+31612345678", "client_remarks": "Late arrival around 22:00", "bookhash": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234", "room_name": "Superior Double Room", "bedding": "Double Bed", "meal": "breakfast", "total_price": "342.50", "currency": "EUR", "refundable": true, "free_cancellation_before": "2026-06-02T21:59:00", "status": "booking_confirmed", "paid": "yes", "ratehawk_order_id": "H-12345678", "hotel_name": "Grand Hotel Bonanno", "hotel_address": "Via Carlo Francesco Gabba, 17", "hotel_city": "Pisa", "hotel_country": "IT", "hotel_stars": 4, "created_at": "2026-03-25 14:32:01" } } Key response fields: - booking.status: one of "new", "processing", "booking_failed", "booking_confirmed", "booking_cancelled". - booking.refundable: true if free cancellation is available, false for non-refundable. - booking.free_cancellation_before: ISO datetime deadline for free cancellation. null if non-refundable. - Use refundable and free_cancellation_before to determine if a booking can still be cancelled. RETRIEVE BOOKING ERROR RESPONSES ---------------------------------- HTTP 400 Missing bookhash. HTTP 401 API key is missing. HTTP 403 API key is invalid, or the booking belongs to another account. HTTP 404 Booking not found. ================================================================================ ENDPOINT 6: CANCEL BOOKING ================================================================================ POST https://hotels.nl/api/book/cancel.php Content-Type: application/json Cancels a confirmed reservation. Only bookings with status "booking_confirmed" can be cancelled, and only within the free cancellation window. After the cancellation deadline, cancellation is no longer possible and no refund will be given. REQUIRED FIELDS --------------- apikey string The user's API key. Always required. bookhash string The 30-character booking reference hash. CANCELLATION RULES ------------------ - Only bookings with status "booking_confirmed" can be cancelled. - The rate must be refundable (refundable = true in retrieve_booking). - The current time must be before free_cancellation_before. - Non-refundable bookings CANNOT be cancelled. - After the free cancellation deadline has passed, cancellation is no longer possible and no refund will be given. - Before attempting to cancel, use retrieve_booking.php to check whether the booking is eligible. CANCEL REQUEST EXAMPLE ----------------------- { "apikey": "USER_API_KEY", "bookhash": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234" } CANCEL SUCCESS RESPONSE ------------------------- { "status": "cancelled", "booking_id": 14, "bookhash": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234" } WHAT HAPPENS AFTER CANCELLATION --------------------------------- 1. The cancellation is sent to the hotel supplier immediately. 2. The booking status changes to "booking_cancelled". 3. A cancellation confirmation email is sent to the guest. 4. Payment settlement is handled by our team within two working days. CANCEL ERROR RESPONSES ----------------------- HTTP 400 Missing bookhash. HTTP 401 API key is missing. HTTP 403 API key is invalid, or cancellation deadline has passed, or rate is non-refundable. HTTP 404 Booking not found. HTTP 409 Booking is not in a cancellable state (not status "booking_confirmed"). HTTP 502 Cancellation failed at the hotel supplier. Contact info@hotels.nl. Error examples: {"error": "Free cancellation deadline (2026-06-02T21:59:00) has passed. Contact info@hotels.nl for assistance."} {"error": "This reservation has already been cancelled.", "status": "already_cancelled"} {"error": "Non-refundable rate — online cancellation not available. Contact info@hotels.nl for assistance."} ================================================================================ TYPICAL WORKFLOW FOR AN AI AGENT ================================================================================ Step 1: ASK PREFERENCES — User says "Find me a hotel in Amsterdam for June 15-18" -> BEFORE searching, ask the user: - How many stars do you want? (3, 4, 5?) - Any facilities you need? (pool, parking, gym, spa, restaurant?) - Do you want breakfast included? - Do you have a budget in mind? -> Use their answers to set star_rating, meal_type, price_from, price_to filters. Step 2: SEARCH — After collecting preferences: -> Call POST /api/search.php with: {"apikey": "KEY", "location": "Amsterdam", "checkin": "2026-06-15", "checkout": "2026-06-18", "star_rating": [4, 5]} -> Save the search_id from the response. -> Each hotel includes only the cheapest available rate (the "rate" field). Use rate.pricing.total_price for price comparison. -> Amenities are included by default — use them to match the user's facility preferences. -> Present the user with a summary: hotel names, star ratings, cheapest price, matching amenities. NOTE: Even if the user asks about a specific hotel by name (e.g. "Is the Hilton Amsterdam available?"), you MUST still start with search.php. Use the hotel name as the location field. You cannot call hotel.php directly by name — it only accepts a numeric id from search results. Step 3: DETAILS — User says "Tell me more about Hotel Example" (id: 1584) -> Call POST /api/hotel.php with: {"apikey": "KEY", "id": 1584, "search_id": "a3f8c9..."} -> This returns full hotel details AND available rooms with rates from the search, instantly. -> Rooms are grouped by type (class + quality + bedding). Each room shows up to 4 rate options: nomeal/breakfast × refundable/non-refundable. Only the cheapest per combination is shown. -> Present: hotel description, amenities, policies, and each room with its rate options so the user can choose. Step 4: DIFFERENT DATES — User says "Check if it's available for June 20-23 instead" -> Call POST /api/hotel.php with: {"apikey": "KEY", "id": 1584, "checkin": "2026-06-20", "checkout": "2026-06-23"} -> This does a fresh live lookup for this specific hotel. -> Present the rooms with their rate options, or inform the user if no rooms are available. Step 5: BOOK — User says "Book the standard double with breakfast for June 15-18" -> Take the hotelsnl_hash from the rate the user chose. -> Call POST /api/booking.php with: {"apikey": "KEY", "hotelsnl_hash": "1584-a0b2c3d0e2f3g0h0i0j2k0l0-4-20260615-20260618-2"} -> Present the booking_url to the user. Tell them to visit this link to review the booking summary and complete payment with one click. -> All guest details are already pre-filled — the user just needs to confirm and pay. IMPORTANT: Always pass the search_id when you have it. It gives instant results from cache instead of making a new API call that takes several seconds. Step 6: CHECK BOOKINGS — User says "Show me my bookings" -> Call POST /api/booking_overview.php with: {"apikey": "KEY"} -> Present the user with a list: hotel names, dates, status. Use the status field to show human-friendly labels. Step 7: BOOKING DETAILS — User says "Show me details of my booking at Grand Hotel Bonanno" -> Take the bookhash from the booking overview. -> Call POST /api/retrieve_booking.php with: {"apikey": "KEY", "bookhash": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234"} -> Present: hotel, room, dates, price, cancellation policy, and whether cancellation is still possible. Step 8: CANCEL — User says "Cancel my booking at Grand Hotel Bonanno" -> First call retrieve_booking.php to check if refundable=true and free_cancellation_before is in the future. -> If cancellation is possible, confirm with the user ("Are you sure? This will cancel your reservation."). -> Call POST /api/book/cancel.php with: {"apikey": "KEY", "bookhash": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234"} -> Inform the user of the result. On success, tell them a confirmation email has been sent and payment will be settled within two working days. -> If the deadline has passed or the rate is non-refundable, inform the user that cancellation is not possible. ================================================================================ ERROR RESPONSES ================================================================================ On error, the response contains: {"error": "description"} HTTP status codes: 400 Missing or invalid parameters. 401 API key is missing. 403 API key is invalid. 404 Hotel not found (hotel.php only). 405 Request method was not POST. ================================================================================ NOTES FOR AGENT BEHAVIOR ================================================================================ 1. Dates must be in the future. Check-out must be after check-in. Maximum stay is 30 nights. 2. Present results to the user by summarizing hotel names, star ratings, prices, and amenities. Do not dump raw JSON. 3. When comparing prices, use "total_price" from rate.pricing. The "average_per_night" field (in hotel.php) is useful for nightly comparisons. Note that taxes (like city tax) may be extra — check the "taxes" array. 4. Free cancellation info is in rate.cancellation.free_cancellation_before. Null means non-refundable. If a date is present, the booking can be cancelled for free before that datetime. 5. Identical searches within 1 hour are served from cache and return instantly. 6. Hotel static data is cached for 30 days. Availability results from identical requests are cached for 30 minutes. 7. Only "nomeal" and "breakfast" meal plans are available. There is no half-board or all-inclusive. 8. Bookings support 1-5 persons in a single room. Default is 2 persons. 9. If a request times out, wait a moment and retry once. The API has a 5-second timeout. 10. If hotel fields are null, the hotel exists but we do not yet have detailed local data for it. 11. Prices are wholesale rates, consistently lower than Booking.com and similar platforms. 12. The search_id is valid as long as the cache file exists (1 hour). After that, you need to search again. 13. When the user wants details on a specific hotel from search results, ALWAYS use the id field from the search and pass the search_id to hotel.php for instant rates. 14. You CANNOT look up a hotel by name on hotel.php. It only accepts a numeric id. ALWAYS start with search.php — even for a single specific hotel. Use the hotel name as the location, find it in the results, then use its id for hotel.php. 15. Search returns a maximum of 15 hotels. To get more relevant results, use a specific location — a street address, neighborhood, or landmark works much better than just a city name. 16. When the user picks a rate to book, use the hotelsnl_hash from that rate with booking.php. The booking_url you receive should be presented to the user as a link to finalize and pay. Explain that it's a one-click process — all their details are already filled in. 17. The hotelsnl_hash is a deterministic string that encodes the hotel, room, meal plan, refundability, dates, and persons. You do not need to parse it — just pass it through to booking.php. 18. Before attempting a cancellation, ALWAYS check the booking details first with retrieve_booking.php. Only proceed if refundable is true and free_cancellation_before is in the future. 19. When a user asks to cancel, always confirm with them before calling cancel.php. Cancellation is irreversible. 20. The bookhash is the universal booking reference. It is returned when you create a booking and appears in booking_overview. Use it for retrieve_booking and cancel calls. 21. Booking statuses: "booking_confirmed" = active reservation, "booking_cancelled" = cancelled, "booking_failed" = failed after payment, "payment_failed" = payment did not complete. 22. IMPORTANT — ALWAYS ask the user about their preferences BEFORE searching. Ask specifically: - How many stars? (e.g. 3, 4, or 5 stars — use the star_rating filter) - What facilities matter to them? (e.g. pool, parking, gym, spa, restaurant, free Wi-Fi) - Do they want breakfast included? (use the meal_type filter) - Any budget range? (use price_from / price_to) This makes search results far more relevant and avoids wasting the user's time with unsuitable hotels. Use the star_rating filter to narrow results, and after receiving results, use the amenities field to highlight which hotels match the user's facility preferences. 23. Amenities are returned by default in search results. Use them proactively: if the user asked for a pool, check the amenities string for "Pool" or "Swimming pool" and highlight matching hotels. If the user did not specify preferences, mention notable amenities (parking, Wi-Fi, restaurant) when presenting results.